Add simple functions to put the current thread to sleep using exponential backoff to split the interval in smaller pieces. Signed-off-by: Lucas De Marchi <lucas.de.marchi@xxxxxxxxx> --- shared/util.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ shared/util.h | 5 +++++ 2 files changed, 51 insertions(+) diff --git a/shared/util.c b/shared/util.c index d4452eb..4b547ff 100644 --- a/shared/util.c +++ b/shared/util.c @@ -472,6 +472,52 @@ unsigned long long ts_msec(const struct timespec *ts) (unsigned long long) ts->tv_nsec / NSEC_PER_MSEC; } +static struct timespec msec_ts(unsigned long long msec) +{ + struct timespec ts = { + .tv_sec = msec / MSEC_PER_SEC, + .tv_nsec = (msec % MSEC_PER_SEC) * NSEC_PER_MSEC, + }; + + return ts; +} + +int sleep_until_msec(unsigned long long msec) +{ + struct timespec ts = msec_ts(msec); + + if (clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &ts, NULL) < 0 && + errno != EINTR) + return -errno; + + return 0; +} + +/* + * Exponential retry backoff with tail + */ +unsigned long long get_backoff_delta_msec(unsigned long long t0, + unsigned long long tend, + unsigned long long *delta) +{ + unsigned long long t; + + t = now_msec(); + + if (!*delta) + *delta = 1; + else + *delta <<= 1; + + while (t + *delta > tend) + *delta >>= 1; + + if (!*delta && tend > t) + *delta = tend - t; + + return t + *delta; +} + unsigned long long now_usec(void) { struct timespec ts; diff --git a/shared/util.h b/shared/util.h index bedafa3..7030653 100644 --- a/shared/util.h +++ b/shared/util.h @@ -55,6 +55,11 @@ unsigned long long ts_usec(const struct timespec *ts); unsigned long long ts_msec(const struct timespec *ts); unsigned long long now_usec(void); unsigned long long now_msec(void); +int sleep_until_msec(unsigned long long msec); +unsigned long long get_backoff_delta_msec(unsigned long long t0, + unsigned long long tend, + unsigned long long *delta); + /* endianess and alignments */ /* ************************************************************************ */ -- 2.36.1