File: //usr/src/glibc/debian/patches/ubuntu/local-fallback-to-monotonic.diff
From 01849fca6c83afa9e7c60a9f1031760f3e283b52 Mon Sep 17 00:00:00 2001
From: Balint Reczey <balint.reczey@canonical.com>
Date: Mon, 27 Jul 2020 18:44:40 +0200
Subject: [PATCH] Fall back to CLOCK_MONOTONIC when clock_nanosleep_time64 with
CLOCK_REALTIME fails
Based on Christian Pfeiffer's patch at
https://gist.github.com/ChrisTX/391fe201b3d72d3b3dac17066100347d
See: https://github.com/microsoft/WSL/issues/4898
---
sysdeps/unix/sysv/linux/clock_nanosleep.c | 38 +++++++++++++++++++++++
1 file changed, 38 insertions(+)
diff --git a/sysdeps/unix/sysv/linux/clock_nanosleep.c b/sysdeps/unix/sysv/linux/clock_nanosleep.c
index 728137aa56..99c5671ff4 100644
--- a/sysdeps/unix/sysv/linux/clock_nanosleep.c
+++ b/sysdeps/unix/sysv/linux/clock_nanosleep.c
@@ -24,6 +24,36 @@
#include <shlib-compat.h>
+
+static int valid_nanosleep_ts (const struct __timespec64 *ts) {
+ return (ts->tv_nsec >= 0 && ts->tv_nsec < 1000000000L && ts->tv_sec >= 0);
+}
+
+/* Use CLOCK_MONOTONIC and convert request with TIMER_ABSTIME to use relative time */
+#define MONOTONIC_FALLBACK do { \
+ if (__glibc_unlikely (flags & TIMER_ABSTIME)) \
+ { \
+ struct __timespec64 current_realtime, actual_req; \
+ actual_req = *req; \
+ if(__clock_gettime64(CLOCK_REALTIME, ¤t_realtime)) \
+ return EINVAL; \
+ actual_req.tv_nsec -= current_realtime.tv_nsec; \
+ actual_req.tv_sec -= current_realtime.tv_sec; \
+ if (actual_req.tv_nsec < 0) \
+ { \
+ --actual_req.tv_sec; \
+ actual_req.tv_nsec = 1000000000L + actual_req.tv_nsec; \
+ } \
+ r = INTERNAL_SYSCALL_CANCEL (clock_nanosleep_time64, \
+ err, CLOCK_MONOTONIC, \
+ flags & ~TIMER_ABSTIME, \
+ &actual_req, rem); \
+ } else \
+ r = INTERNAL_SYSCALL_CANCEL (clock_nanosleep_time64, \
+ err, CLOCK_MONOTONIC, flags, \
+ req, rem); \
+ } while (0)
+
/* We can simply use the syscall. The CPU clocks are not supported
with this function. */
int
@@ -47,10 +77,18 @@ __clock_nanosleep_time64 (clockid_t clock_id, int flags, const struct __timespec
# endif
r = INTERNAL_SYSCALL_CANCEL (clock_nanosleep_time64, err, clock_id,
flags, req, rem);
+ if (__glibc_unlikely (INTERNAL_SYSCALL_ERRNO (r, err) == EINVAL
+ && clock_id == CLOCK_REALTIME
+ && valid_nanosleep_ts(req)))
+ MONOTONIC_FALLBACK;
#else
# ifdef __NR_clock_nanosleep_time64
r = INTERNAL_SYSCALL_CANCEL (clock_nanosleep_time64, err, clock_id,
flags, req, rem);
+ if (__glibc_unlikely (INTERNAL_SYSCALL_ERRNO (r, err) == EINVAL
+ && clock_id == CLOCK_REALTIME
+ && valid_nanosleep_ts(req)))
+ MONOTONIC_FALLBACK;
if (! INTERNAL_SYSCALL_ERROR_P (r, err))
return 0;
--
2.25.1