]> git.ipfire.org Git - thirdparty/kmod.git/commitdiff
util: Add exponential backoff sleep
authorLucas De Marchi <lucas.de.marchi@gmail.com>
Fri, 3 Jun 2022 21:50:45 +0000 (14:50 -0700)
committerLucas De Marchi <lucas.de.marchi@gmail.com>
Mon, 27 Jun 2022 06:23:46 +0000 (23:23 -0700)
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@gmail.com>
shared/util.c
shared/util.h

index d4452eb3589d4408a2974195c6c5e594d53fd8af..4b547ffc4c72b818aba0df04152186c550deeead 100644 (file)
@@ -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;
index bedafa38094edb77c3ec097b34017fec340ad3cb..7030653cac13cbdb10cb22cb7e9aca21b68cded0 100644 (file)
@@ -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                                                 */
 /* ************************************************************************ */