91 lines
3.2 KiB
C
91 lines
3.2 KiB
C
// calogTime.c -- calog time library (see calogTime.h). Three stateless natives over the
|
|
// POSIX clocks: a wall-clock read, a monotonic read, and a millisecond sleep. No shared
|
|
// state and no timers/threads -- each native is a pure function of its arguments (or a
|
|
// plain block of the calling context thread).
|
|
|
|
#define _POSIX_C_SOURCE 200809L
|
|
|
|
#include "calogTime.h"
|
|
|
|
#include <errno.h>
|
|
#include <time.h>
|
|
|
|
static int32_t timeMonotonicNative(CalogValueT *args, int32_t argCount, CalogValueT *result, void *userData);
|
|
static int32_t timeNowNative(CalogValueT *args, int32_t argCount, CalogValueT *result, void *userData);
|
|
static int32_t timeSleepNative(CalogValueT *args, int32_t argCount, CalogValueT *result, void *userData);
|
|
static double timeToSeconds(const struct timespec *ts);
|
|
|
|
|
|
int32_t calogTimeRegister(CalogT *calog) {
|
|
calogRegisterInline(calog, "timeNow", timeNowNative, NULL);
|
|
calogRegisterInline(calog, "timeMonotonic", timeMonotonicNative, NULL);
|
|
calogRegisterInline(calog, "timeSleep", timeSleepNative, NULL);
|
|
return calogOkE;
|
|
}
|
|
|
|
|
|
static int32_t timeMonotonicNative(CalogValueT *args, int32_t argCount, CalogValueT *result, void *userData) {
|
|
struct timespec ts;
|
|
|
|
(void)args;
|
|
(void)userData;
|
|
calogValueNil(result);
|
|
if (argCount != 0) {
|
|
return calogFail(result, calogErrArgE, "timeMonotonic expects ()");
|
|
}
|
|
if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
|
|
return calogFail(result, calogErrUnsupportedE, "timeMonotonic: clock_gettime failed");
|
|
}
|
|
calogValueReal(result, timeToSeconds(&ts));
|
|
return calogOkE;
|
|
}
|
|
|
|
|
|
static int32_t timeNowNative(CalogValueT *args, int32_t argCount, CalogValueT *result, void *userData) {
|
|
struct timespec ts;
|
|
|
|
(void)args;
|
|
(void)userData;
|
|
calogValueNil(result);
|
|
if (argCount != 0) {
|
|
return calogFail(result, calogErrArgE, "timeNow expects ()");
|
|
}
|
|
if (clock_gettime(CLOCK_REALTIME, &ts) != 0) {
|
|
return calogFail(result, calogErrUnsupportedE, "timeNow: clock_gettime failed");
|
|
}
|
|
calogValueReal(result, timeToSeconds(&ts));
|
|
return calogOkE;
|
|
}
|
|
|
|
|
|
static int32_t timeSleepNative(CalogValueT *args, int32_t argCount, CalogValueT *result, void *userData) {
|
|
struct timespec request;
|
|
struct timespec remaining;
|
|
double ms;
|
|
int64_t nanos;
|
|
|
|
(void)userData;
|
|
calogValueNil(result);
|
|
if (argCount != 1 || (args[0].type != calogIntE && args[0].type != calogRealE)) {
|
|
return calogFail(result, calogErrArgE, "timeSleep expects (milliseconds)");
|
|
}
|
|
ms = (args[0].type == calogIntE) ? (double)args[0].as.i : args[0].as.r;
|
|
if (!(ms >= 0.0)) {
|
|
return calogFail(result, calogErrRangeE, "timeSleep: milliseconds must be non-negative");
|
|
}
|
|
nanos = (int64_t)(ms * 1000000.0);
|
|
request.tv_sec = (time_t)(nanos / 1000000000);
|
|
request.tv_nsec = (long)(nanos % 1000000000);
|
|
while (nanosleep(&request, &remaining) != 0) {
|
|
if (errno != EINTR) {
|
|
return calogFail(result, calogErrUnsupportedE, "timeSleep: nanosleep failed");
|
|
}
|
|
request = remaining;
|
|
}
|
|
return calogOkE;
|
|
}
|
|
|
|
|
|
static double timeToSeconds(const struct timespec *ts) {
|
|
return (double)ts->tv_sec + (double)ts->tv_nsec / 1000000000.0;
|
|
}
|