From bb0553e4c40d32d3c96a001b214b93d6561b9a1b Mon Sep 17 00:00:00 2001 From: Miroslav Lichvar Date: Wed, 11 Mar 2020 08:56:17 +0100 Subject: [PATCH] sched: provide low-precision monotonic time Measure the interval since the start in order to provide a monotonic time for periodical tasks not using timers like driftfile updates, key refresh, etc. Return the interval in the double format, but keep an integer remainder limiting the precision to 0.01 second to avoid issues with very small increments in a long-running process. --- sched.c | 43 +++++++++++++++++++++++++++++++++++++++++++ sched.h | 3 +++ 2 files changed, 46 insertions(+) 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);