diff mbox series

[6/8] util: Add exponential backoff sleep

Message ID 20220603215047.9607-7-lucas.de.marchi@gmail.com (mailing list archive)
State New
Headers show
Series Add --wait to modprobe -r | expand

Commit Message

Lucas De Marchi June 3, 2022, 9:50 p.m. UTC
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 | 46 ++++++++++++++++++++++++++++++++++++++++++++++
 shared/util.h |  5 +++++
 2 files changed, 51 insertions(+)
diff mbox series

Patch

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                                                 */
 /* ************************************************************************ */