From 664fc63a246cba97e202f712aa48105f46a9ff69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Mon, 12 Dec 2022 11:34:51 +0200 Subject: [PATCH] systemclock: Use `futex_time64` syscall on x32 and other platforms that always use a 32-bit `struct timespec` for the normal `futex` syscall See also https://gitlab.gnome.org/GNOME/glib/-/issues/2634 --- gst/gstsystemclock.c | 26 +++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/gst/gstsystemclock.c b/gst/gstsystemclock.c index 6d0b6ec47b6..8c396d2c7b4 100644 --- a/gst/gstsystemclock.c +++ b/gst/gstsystemclock.c @@ -130,7 +130,31 @@ gst_futex_cond_broadcast (guint * cond_val) static gboolean gst_futex_cond_wait_until (guint * cond_val, GMutex * mutex, gint64 end_time) { + /* On x32 (ILP32 ABI on x86_64) and potentially sparc64, the raw futex() + * syscall takes a 32-bit timespan argument *regardless* of whether userspace + * is using 32-bit or 64-bit `struct timespec`. This means that we can’t + * unconditionally pass a `struct timespec` pointer into the syscall. + * + * Assume that any such platform is new enough to define the + * `__NR_futex_time64` workaround syscall (which accepts 64-bit timespecs, + * introduced in kernel 5.1), and use that to pass a 64-bit timespec instead. + * + * `clock_gettime()` on such systems will either return a 32-bit `struct + * timespec`, in which case the values we will get passed in here are + * already not y2038-safe, or `struct timespec` is using 64-bit `time_t` and + * everything is fine. + */ +#ifdef __NR_futex_time64 + struct + { + gint64 tv_sec; + gint64 tv_nsec; + } end; + const long int futex_syscall_id = __NR_futex_time64; +#else struct timespec end; + const long int futex_syscall_id = __NR_futex; +#endif guint sampled; int res; gboolean success; @@ -146,7 +170,7 @@ gst_futex_cond_wait_until (guint * cond_val, GMutex * mutex, gint64 end_time) /* we use FUTEX_WAIT_BITSET_PRIVATE rather than FUTEX_WAIT_PRIVATE to be * able to use absolute time */ res = - syscall (__NR_futex, cond_val, (gsize) FUTEX_WAIT_BITSET_PRIVATE, + syscall (futex_syscall_id, cond_val, (gsize) FUTEX_WAIT_BITSET_PRIVATE, (gsize) sampled, &end, NULL, FUTEX_BITSET_MATCH_ANY); success = (res < 0 && errno == ETIMEDOUT) ? FALSE : TRUE; g_mutex_lock (mutex); -- GitLab