diff --git a/sched.c b/sched.c index 3c5dc11..559c4a2 100644 --- a/sched.c +++ b/sched.c @@ -65,6 +65,12 @@ static ARR_Instance file_handlers; static struct timespec last_select_ts, last_select_ts_raw; static double last_select_ts_err; +#define TS_MONO_PRECISION_NS 10000000U + +/* Monotonic low-precision timestamp measuring interval since the start */ +static double last_select_ts_mono; +static uint32_t last_select_ts_mono_ns; + /* ================================================== */ /* Variables to handler the timer queue */ @@ -136,6 +142,8 @@ SCH_Initialise(void) LCL_ReadRawTime(&last_select_ts_raw); last_select_ts = last_select_ts_raw; + last_select_ts_mono = 0.0; + last_select_ts_mono_ns = 0; initialised = 1; } @@ -249,6 +257,14 @@ SCH_GetLastEventTime(struct timespec *cooked, double *err, struct timespec *raw) /* ================================================== */ +double +SCH_GetLastEventMonoTime(void) +{ + return last_select_ts_mono; +} + +/* ================================================== */ + #define TQE_ALLOC_QUANTUM 32 static TimerQueueEntry * @@ -722,6 +738,31 @@ check_current_time(struct timespec *prev_raw, struct timespec *raw, int timeout, /* ================================================== */ +static void +update_monotonic_time(struct timespec *now, struct timespec *before) +{ + struct timespec diff; + + /* Avoid frequent floating-point operations and handle small + increments to a large value */ + + UTI_DiffTimespecs(&diff, now, before); + if (diff.tv_sec == 0) { + last_select_ts_mono_ns += diff.tv_nsec; + } else { + last_select_ts_mono += fabs(UTI_TimespecToDouble(&diff) + + last_select_ts_mono_ns / 1.0e9); + last_select_ts_mono_ns = 0; + } + + if (last_select_ts_mono_ns > TS_MONO_PRECISION_NS) { + last_select_ts_mono += last_select_ts_mono_ns / 1.0e9; + last_select_ts_mono_ns = 0; + } +} + +/* ================================================== */ + void SCH_MainLoop(void) { @@ -778,6 +819,8 @@ SCH_MainLoop(void) LCL_CookTime(&now, &cooked, &err); } + update_monotonic_time(&cooked, &last_select_ts); + last_select_ts_raw = now; last_select_ts = cooked; last_select_ts_err = err; diff --git a/sched.h b/sched.h index b7d4279..0d3b311 100644 --- a/sched.h +++ b/sched.h @@ -65,6 +65,9 @@ extern void SCH_SetFileHandlerEvent(int fd, int event, int enable); /* Get the time stamp taken after a file descriptor became ready or a timeout expired */ extern void SCH_GetLastEventTime(struct timespec *cooked, double *err, struct timespec *raw); +/* Get a low-precision monotonic timestamp (starting at 0.0) */ +extern double SCH_GetLastEventMonoTime(void); + /* This queues a timeout to elapse at a given (raw) local time */ extern SCH_TimeoutID SCH_AddTimeout(struct timespec *ts, SCH_TimeoutHandler handler, SCH_ArbitraryArgument arg);