[glib/glib-2-72: 1/39] gthread: Fix futex timespec type on 32-bit kernels with 64-bit userspace
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib/glib-2-72: 1/39] gthread: Fix futex timespec type on 32-bit kernels with 64-bit userspace
- Date: Tue, 20 Sep 2022 19:07:38 +0000 (UTC)
commit 7d63f9446c6c94740204492673e808d97ab54809
Author: Philip Withnall <pwithnall endlessos org>
Date: Tue Apr 26 11:50:23 2022 +0100
gthread: Fix futex timespec type on 32-bit kernels with 64-bit userspace
The `struct timespec` type documented as being passed to the `futex()`
syscall actually needs to be the *kernel’s* timespec type. This will be
a different width from the userspace timespec type if running a 64-bit
userspace on a 32-bit kernel.
That mismatch will cause `g_cond_wait_until()` to return `FALSE`
immediately.
No other uses of `futex()` in GLib use the timeout argument, so they’re
all OK.
Following a detailed suggestion by Rich Felker, pass a different
timespec type into `futex()` if `__NR_futex_time64` is defined. That’s
the 64-bit time version of `futex()` which was added in kernel 5.1, and
which was only added for 32-bit kernels.
Signed-off-by: Philip Withnall <pwithnall endlessos org>
Fixes: #2634
(cherry-picked from commit eec65c761bb406beccf674e371ea38b231136707)
glib/gthread-posix.c | 33 ++++++++++++++++++++++++++++++++-
1 file changed, 32 insertions(+), 1 deletion(-)
---
diff --git a/glib/gthread-posix.c b/glib/gthread-posix.c
index 8e2e66db54..8c403f975a 100644
--- a/glib/gthread-posix.c
+++ b/glib/gthread-posix.c
@@ -1599,6 +1599,13 @@ g_cond_wait_until (GCond *cond,
{
struct timespec now;
struct timespec span;
+#ifdef __NR_futex_time64
+ long span_arg[2];
+ G_STATIC_ASSERT (sizeof (span_arg[0]) == 4);
+#else
+ struct timespec span_arg;
+#endif
+
guint sampled;
int res;
gboolean success;
@@ -1618,9 +1625,33 @@ g_cond_wait_until (GCond *cond,
if (span.tv_sec < 0)
return FALSE;
+ /* 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 as a proxy for whether to pass in
+ * `long[2]` or `struct timespec`.
+ *
+ * As per https://lwn.net/Articles/776427/, the `time64` syscalls only exist
+ * on 32-bit platforms, so in this case `sizeof(long)` should always be
+ * 32 bits.
+ *
+ * Don’t bother actually calling `__NR_futex_time64` as the `span` is relative
+ * and hence very unlikely to overflow, even if using 32-bit longs.
+ */
+#ifdef __NR_futex_time64
+ span_arg[0] = span.tv_sec;
+ span_arg[1] = span.tv_nsec;
+#else
+ span_arg = span;
+#endif
+
sampled = cond->i[0];
g_mutex_unlock (mutex);
- res = syscall (__NR_futex, &cond->i[0], (gsize) FUTEX_WAIT_PRIVATE, (gsize) sampled, &span);
+ res = syscall (__NR_futex, &cond->i[0], (gsize) FUTEX_WAIT_PRIVATE, (gsize) sampled, &span_arg);
success = (res < 0 && errno == ETIMEDOUT) ? FALSE : TRUE;
g_mutex_lock (mutex);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]