[RFC PATCH 1/2] linux: Add futex_wait, futex_timedwait, futex_wake, and futex_requeue

Adhemerval Zanella adhemerval.zanella@linaro.org
Tue Aug 25 16:37:19 GMT 2026


Add a new installed header <sys/futex.h> with thin wrappers around the safe
subset of the futex system call.  It provides a blocking building block for
implementing custom synchronization primitives:

  int futex_wait (uint32_t *futexp, uint32_t expected, unsigned int flags);

  int futex_timedwait (uint32_t *futexp, uint32_t expected, clockid_t clockid,
		       const struct timespec *abstime, unsigned int flags);

  int futex_wake (uint32_t *futexp, int count, unsigned int flags);

  int futex_requeue (uint32_t *futexp, uint32_t expected, int nwake,
		     uint32_t *targetp, int nrequeue, unsigned int flags);

The flags argument may be zero (process-shared) or FUTEX_FLAG_PRIVATE, which
follows the kernel FUTEX_PRIVATE_FLAG value so that the same value is shared
with the futex_waitv per-waiter FUTEX2_PRIVATE flag. The wait functions
return 0 on success; futex_wake and futex_requeue return the number of threads
that were woken or requeued.  On failure, all functions return -1 and set errno,
following the usual syscall wrapper convention.  The functions are not
cancellation points.

Only the well-defined subset of the kernel interface is exposed. The
futex_timedwait takes an absolute timeout with an explicit clockid (implemented
with FUTEX_WAIT_BITSET to avoid the relative-only CLOCK_MONOTONIC FUTEX_WAIT
quirk), and futex_requeue only maps to the FUTEX_CMP_REQUEUE operation.

The futex_timedwait function supports both 32-bit and 64-bit time_t values.

Checked on x86_64-linux-gnu and i686-linux-gnu.
---
 NEWS                                          |   5 +-
 include/sys/futex.h                           |  27 +++
 manual/threads.texi                           | 128 +++++++++++++
 nptl/futex-internal.c                         |  32 ++++
 sysdeps/nptl/futex-internal.h                 |  58 +++---
 sysdeps/nptl/lowlevellock-futex.h             |  12 ++
 sysdeps/unix/sysv/linux/Makefile              |   7 +
 sysdeps/unix/sysv/linux/Versions              |   9 +
 sysdeps/unix/sysv/linux/aarch64/libc.abilist  |   4 +
 sysdeps/unix/sysv/linux/alpha/libc.abilist    |   4 +
 sysdeps/unix/sysv/linux/arc/libc.abilist      |   4 +
 sysdeps/unix/sysv/linux/arm/be/libc.abilist   |   5 +
 sysdeps/unix/sysv/linux/arm/le/libc.abilist   |   5 +
 sysdeps/unix/sysv/linux/csky/libc.abilist     |   5 +
 sysdeps/unix/sysv/linux/futex_requeue.c       |  35 ++++
 sysdeps/unix/sysv/linux/futex_timedwait.c     |  55 ++++++
 sysdeps/unix/sysv/linux/futex_wait.c          |  36 ++++
 sysdeps/unix/sysv/linux/futex_wake.c          |  38 ++++
 sysdeps/unix/sysv/linux/hppa/libc.abilist     |   5 +
 sysdeps/unix/sysv/linux/i386/libc.abilist     |   5 +
 .../sysv/linux/loongarch/ilp32/libc.abilist   |   4 +
 .../sysv/linux/loongarch/lp64/libc.abilist    |   4 +
 .../sysv/linux/m68k/coldfire/libc.abilist     |   5 +
 .../unix/sysv/linux/m68k/m680x0/libc.abilist  |   5 +
 .../sysv/linux/microblaze/be/libc.abilist     |   5 +
 .../sysv/linux/microblaze/le/libc.abilist     |   5 +
 .../sysv/linux/mips/mips32/fpu/libc.abilist   |   5 +
 .../sysv/linux/mips/mips32/nofpu/libc.abilist |   5 +
 .../sysv/linux/mips/mips64/n32/libc.abilist   |   5 +
 .../sysv/linux/mips/mips64/n64/libc.abilist   |   4 +
 sysdeps/unix/sysv/linux/or1k/libc.abilist     |   4 +
 .../linux/powerpc/powerpc32/fpu/libc.abilist  |   5 +
 .../powerpc/powerpc32/nofpu/libc.abilist      |   5 +
 .../linux/powerpc/powerpc64/be/libc.abilist   |   4 +
 .../linux/powerpc/powerpc64/le/libc.abilist   |   4 +
 .../unix/sysv/linux/riscv/rv32/libc.abilist   |   4 +
 .../unix/sysv/linux/riscv/rv64/libc.abilist   |   4 +
 sysdeps/unix/sysv/linux/s390/libc.abilist     |   4 +
 sysdeps/unix/sysv/linux/sh/be/libc.abilist    |   5 +
 sysdeps/unix/sysv/linux/sh/le/libc.abilist    |   5 +
 .../sysv/linux/sparc/sparc32/libc.abilist     |   5 +
 .../sysv/linux/sparc/sparc64/libc.abilist     |   4 +
 sysdeps/unix/sysv/linux/sys/futex.h           |  85 +++++++++
 sysdeps/unix/sysv/linux/tst-futex-time64.c    |   1 +
 sysdeps/unix/sysv/linux/tst-futex.c           | 179 ++++++++++++++++++
 .../unix/sysv/linux/x86_64/64/libc.abilist    |   4 +
 .../unix/sysv/linux/x86_64/x32/libc.abilist   |   4 +
 47 files changed, 828 insertions(+), 24 deletions(-)
 create mode 100644 include/sys/futex.h
 create mode 100644 sysdeps/unix/sysv/linux/futex_requeue.c
 create mode 100644 sysdeps/unix/sysv/linux/futex_timedwait.c
 create mode 100644 sysdeps/unix/sysv/linux/futex_wait.c
 create mode 100644 sysdeps/unix/sysv/linux/futex_wake.c
 create mode 100644 sysdeps/unix/sysv/linux/sys/futex.h
 create mode 100644 sysdeps/unix/sysv/linux/tst-futex-time64.c
 create mode 100644 sysdeps/unix/sysv/linux/tst-futex.c

diff --git a/NEWS b/NEWS
index 56c6b581df..805a71b639 100644
--- a/NEWS
+++ b/NEWS
@@ -9,7 +9,10 @@ Version 2.45
 
 Major new features:
 
-  [Add new features here]
+* On Linux, the functions futex_wait, futex_timedwait, futex_wake, and
+  futex_requeue have been added.  They are wrappers around a subset of
+  the futex system call and provide the blocking building block for
+  implementing custom synchronization primitives.
 
 Deprecated and removed features, and other changes affecting compatibility:
 
diff --git a/include/sys/futex.h b/include/sys/futex.h
new file mode 100644
index 0000000000..602096a738
--- /dev/null
+++ b/include/sys/futex.h
@@ -0,0 +1,27 @@
+#ifndef _SYS_FUTEX_H
+#include_next <sys/futex.h>
+
+# ifndef _ISOMAC
+
+# include <futex-internal.h>
+# include <struct___timespec64.h>
+
+static __always_inline _Bool
+__futex_check_flags (unsigned int flags)
+{
+  return (flags & ~(unsigned int) FUTEX_PRIVATE_FLAG) == 0;
+}
+
+# if __TIMESIZE == 64
+#  define __futex_timedwait_time64 futex_timedwait
+# else
+extern int __futex_timedwait_time64 (uint32_t *futexp, uint32_t expected,
+				     clockid_t clockid,
+				     const struct __timespec64 *abstime,
+				     unsigned int flags)
+     __nonnull ((1));
+libc_hidden_proto (__futex_timedwait_time64)
+# endif
+
+# endif /* !_ISOMAC */
+#endif
diff --git a/manual/threads.texi b/manual/threads.texi
index 0331599bc0..16c716f0ab 100644
--- a/manual/threads.texi
+++ b/manual/threads.texi
@@ -1151,6 +1151,8 @@ the standard.
 * Single-Threaded::                       Detecting single-threaded execution.
 * Restartable Sequences::                 Linux-specific restartable sequences
                                           integration.
+* Futexes::                               Linux-specific fast userspace
+                                          locking primitives.
 @end menu
 
 @node Default Thread Attributes
@@ -1547,6 +1549,132 @@ abort handler.  Failure to provide the expected signature may terminate
 the process with a segmentation fault.
 @end deftypevr
 
+@node Futexes
+@subsubsection Futexes
+@cindex futex
+
+This section describes the futex functions, which are wrappers around
+the Linux @code{futex} system call.  This functionality is only
+available on Linux.
+
+A futex consists of a 32-bit @dfn{futex word} value in memory, and
+kernel state associated with the address of the futex word.  The
+@code{futex} functions allow a thread to block until the futex word
+changes and to wake threads blocked on a futex word.  Along with atomic
+operations on the futex (done in userland), they provide the blocking
+building block for arbitrary synchronization primitives such as mutexes,
+condition variables, and event counts.
+
+These functions do not provide a lock or condition variable abstraction on
+their own, and their correct use requires some care.  On failure, they
+return @minus{}1 and set @code{errno} (as for calling futex through
+@code{syscall}); they are not a cancellation entrypoint, and they are
+async-signal-safe.
+
+A wait on a futex may return spuriously, reporting a wake-up even though no
+matching wake operation was issued.  Callers must re-check the futex word
+after a wait returns and, if necessary, wait again.
+
+Each function has a @var{flags} argument which may be zero or
+@code{FUTEX_FLAG_PRIVATE}.  @code{FUTEX_FLAG_PRIVATE} declares that the
+futex word is only used by threads of the calling process, which allows
+the kernel to use faster process-local bookkeeping.  Without it, the
+futex word may be accessed by multiple processes through a shared
+memory mapping (@code{MAP_SHARED}).  Waiters and wakers of one futex
+word must agree on this flag.  The value follows the kernel
+@code{FUTEX_PRIVATE_FLAG}.
+
+@deftypefun int futex_wait (uint32_t *@var{futexp}, uint32_t @var{expected}, unsigned int @var{flags})
+@standards{Linux, sys/futex.h}
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+If the @code{futexp} word content is equal to the value @var{expected},
+block until the calling thread is woken by @code{futex_wake} (or spuriously).
+The check of the futex word and the blocking are performed atomically with
+respect to concurrent futex operations on @var{futexp}.  This guarantees
+that no wake-up which is issued after the check can be missed.
+
+The return value is zero if the thread was woken, or @minus{}1 with
+@code{errno} set to one of the following error codes:
+
+@table @code
+@item EAGAIN
+The futex value did not contain @var{expected} at the time of the call.
+
+@item EINTR
+The wait was interrupted by a signal handler.
+
+@item EINVAL
+@var{futexp} is not aligned to four bytes, or @var{flags} is invalid.
+@end table
+@end deftypefun
+
+@deftypefun int futex_timedwait (uint32_t *@var{futexp}, uint32_t @var{expected}, clockid_t @var{clockid}, const struct timespec *@var{abstime}, unsigned int @var{flags})
+@standards{Linux, sys/futex.h}
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+Like @code{futex_wait}, but block at most until the absolute time @var{abstime},
+measured against the clock @var{clockid}.  The @var{clockid} must be either
+@code{CLOCK_REALTIME} or @code{CLOCK_MONOTONIC}.  If @var{abstime} is @code{NULL},
+block without a timeout.
+
+In addition to the @code{futex_wait} error codes, the following error
+codes can be set:
+
+@table @code
+@item ETIMEDOUT
+The absolute time @var{abstime} passed before the thread was woken.
+An @var{abstime} that already expired is reported as @code{ETIMEDOUT}.
+
+@item EOVERFLOW
+@var{abstime} cannot be represented in the time type used by the
+kernel interface.
+@end table
+@end deftypefun
+
+@deftypefun int futex_wake (uint32_t *@var{futexp}, int @var{count}, unsigned int @var{flags})
+@standards{Linux, sys/futex.h}
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+Wake up to @var{count} threads blocked on the @code{futexp} word.
+Using @code{INT_MAX} wake all threads waiting of the futex.
+
+The return value is the number of threads actually woken, which is
+zero if no thread was blocked, or @minus{}1 with @code{errno} set to
+@code{EINVAL} if @var{futexp} is not aligned to four bytes,
+@var{count} is negative, or @var{flags} is not valid.
+@end deftypefun
+
+@deftypefun int futex_requeue (uint32_t *@var{futexp}, uint32_t @var{expected}, int @var{nwake}, uint32_t *@var{targetp}, int @var{nrequeue}, unsigned int @var{flags})
+@standards{Linux, sys/futex.h}
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+If the @code{futexp} word  still contains the value @var{expected}, wake upto
+@var{nwake} threads blocked on @var{futexp} and transfer up to @var{nrequeue}
+of the remaining blocked threads to the waitqueue of the futex word
+@var{targetp}, without waking them.
+
+Requeueing avoids the ``thundering herd'' effect of waking all threads, only
+for most of them to immediately block on another futex again.   For example,
+a condition variable broadcast can wake one thread and requeue the others to
+the futex that implements the associated mutex.  The value check makes the
+operation race-free, as with @code{futex_wait}.  Both futex words must use
+the same @var{flags}.
+
+The return value is the total number of woken and requeued threads, or
+@minus{}1 with @code{errno} set to one of the following error codes:
+
+@table @code
+@item EAGAIN
+The futex word did not contain the value @var{expected} at the time of
+the call.
+
+@item EFAULT
+@var{futexp} or @var{targetp} do not point to accessible memory.
+
+@item EINVAL
+@var{futexp} or @var{targetp} are not aligned to four bytes or are the
+same address, @var{nwake} or @var{nrequeue} are negative, or
+@var{flags} is not valid.
+@end table
+@end deftypefun
+
 @c FIXME these are undocumented:
 @c pthread_atfork
 @c pthread_attr_destroy
diff --git a/nptl/futex-internal.c b/nptl/futex-internal.c
index 3a609a359f..22de30dcfa 100644
--- a/nptl/futex-internal.c
+++ b/nptl/futex-internal.c
@@ -141,6 +141,38 @@ __futex_abstimed_wait_cancelable64 (unsigned int* futex_word,
 }
 libc_hidden_def (__futex_abstimed_wait_cancelable64)
 
+int
+__futex_abstimed_wait64_errno (unsigned int* futex_word,
+                               unsigned int expected, clockid_t clockid,
+                               const struct __timespec64* abstime,
+                               unsigned int flags)
+{
+  int err = __futex_abstimed_wait_common (futex_word, expected, clockid,
+                                          abstime,
+                                          flags ^ FUTEX_PRIVATE_FLAG, false);
+  if (__glibc_likely (err == 0))
+    return 0;
+  __set_errno (err);
+  return -1;
+}
+libc_hidden_def (__futex_abstimed_wait64_errno)
+
+int
+__futex_cmp_requeue_errno (unsigned int *futex_word, unsigned int expected,
+                           int nr_wake, unsigned int *target_word,
+                           int nr_requeue, unsigned int flags)
+{
+  int r = lll_futex_syscall_ret (6, futex_word, FUTEX_CMP_REQUEUE | flags,
+                                 nr_wake, nr_requeue, target_word, expected);
+  if (__glibc_unlikely (r < 0))
+    {
+      __set_errno (-r);
+      return -1;
+    }
+  return r;
+}
+libc_hidden_def (__futex_cmp_requeue_errno)
+
 int
 __futex_lock_pi64 (int *futex_word, clockid_t clockid,
 		   const struct __timespec64 *abstime, int private)
diff --git a/sysdeps/nptl/futex-internal.h b/sysdeps/nptl/futex-internal.h
index 399460a642..b7252cc6ef 100644
--- a/sysdeps/nptl/futex-internal.h
+++ b/sysdeps/nptl/futex-internal.h
@@ -179,31 +179,20 @@ __futex_abstimed_supported_clockid (clockid_t clockid)
      }
      return res;
 
-   Note that we need to support futex_wake calls to past futexes whose memory
+   Returns the number of woken processes, or a negated error code.  Note
+   that we need to support futex_wake calls to past futexes whose memory
    has potentially been reused due to POSIX' requirements on synchronization
-   object destruction (see above); therefore, we must not report or abort
-   on most errors.  */
-static __always_inline void
-__futex_wake_internal (unsigned int* futex_word, int processes_to_wake, int private)
+   object destruction (see above); therefore -EFAULT (memory reuse) and
+   -EINVAL (either incorrect alignment or memory reused for a PI futex)
+   can occur in correct executions, and internal callers simply ignore
+   the return value.  */
+static __always_inline int
+__futex_wake_internal (unsigned int *futex_word, int processes_to_wake,
+		       int private)
 {
-  int res = lll_futex_wake (futex_word, processes_to_wake, private);
-  /* No error.  Ignore the number of woken processes.  */
-  if (res >= 0)
-    return;
-  switch (res)
-    {
-    case -EFAULT: /* Could have happened due to memory reuse.  */
-    case -EINVAL: /* Could be either due to incorrect alignment (a bug in
-		     glibc or in the application) or due to memory being
-		     reused for a PI futex.  We cannot distinguish between the
-		     two causes, and one of them is correct use, so we do not
-		     act in this case.  */
-      return;
-    case -ENOSYS: /* Must have been caused by a glibc bug.  */
-    /* No other errors are documented at this time.  */
-    default:
-      __futex_fatal_error ();
-    }
+  return lll_futex_syscall_ret (4, futex_word,
+				__lll_private_flag (FUTEX_WAKE, private),
+				processes_to_wake, 0);
 }
 
 /* The operation checks the value of the futex, if the value is 0, then
@@ -293,6 +282,29 @@ __futex_abstimed_wait64 (unsigned int* futex_word, unsigned int expected,
 libc_hidden_proto (__futex_abstimed_wait64);
 
 
+/* The following wrappers are used to implement the public futex interfaces.
+   Unlike the wrappers above, they do not abort on any error, and the value
+   returned by a successful futex operation is preserved.  */
+
+/* Like __futex_abstimed_wait64, but return 0 on success or -1 with errno
+   set on failure.  */
+int
+__futex_abstimed_wait64_errno (unsigned int *futex_word,
+			       unsigned int expected, clockid_t clockid,
+			       const struct __timespec64 *abstime,
+			       unsigned int flags);
+libc_hidden_proto (__futex_abstimed_wait64_errno)
+
+/* If *FUTEX_WORD == EXPECTED, wake up to NR_WAKE waiters on FUTEX_WORD and
+   requeue up to NR_REQUEUE of the remaining waiters to TARGET_WORD.  Returns
+   the total number of woken and requeued waiters, or -1 with  errno set on
+   failure.  */
+int
+__futex_cmp_requeue_errno (unsigned int *futex_word, unsigned int expected,
+			   int nr_wake, unsigned int *target_word,
+			   int nr_requeue, unsigned int flags);
+libc_hidden_proto (__futex_cmp_requeue_errno)
+
 static __always_inline int
 __futex_clocklock64 (int *futex, clockid_t clockid,
                      const struct __timespec64 *abstime, int private)
diff --git a/sysdeps/nptl/lowlevellock-futex.h b/sysdeps/nptl/lowlevellock-futex.h
index 6408613501..413eaac32e 100644
--- a/sysdeps/nptl/lowlevellock-futex.h
+++ b/sysdeps/nptl/lowlevellock-futex.h
@@ -61,6 +61,18 @@
      ? -INTERNAL_SYSCALL_ERRNO (__ret) : 0);                     	\
   })
 
+/* Like lll_futex_syscall, but preserve the value returned by a
+   successful futex operation (for instance the number of woken or
+   requeued waiters for FUTEX_WAKE and FUTEX_CMP_REQUEUE): the result
+   is either a non-negative success value or a negated errno code.  */
+# define lll_futex_syscall_ret(nargs, futexp, op, ...)                  \
+  ({                                                                    \
+    long int __ret = INTERNAL_SYSCALL (futex, nargs, futexp, op, 	\
+				       __VA_ARGS__);                    \
+    (__glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (__ret))         	\
+     ? -INTERNAL_SYSCALL_ERRNO (__ret) : __ret);                        \
+  })
+
 /* For most of these macros, the return value is never really used.
    Nevertheless, the protocol is that each one returns a negated errno
    code for failure or zero for success.  (Note that the corresponding
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
index a505253d17..f6c4672a07 100644
--- a/sysdeps/unix/sysv/linux/Makefile
+++ b/sysdeps/unix/sysv/linux/Makefile
@@ -74,6 +74,10 @@ sysdep_routines += \
   eventfd_read \
   eventfd_write \
   fanotify_mark \
+  futex_requeue \
+  futex_timedwait \
+  futex_wait \
+  futex_wake \
   fxstat \
   fxstat64 \
   fxstatat \
@@ -169,6 +173,7 @@ sysdep_headers += \
   sys/eventfd.h \
   sys/fanotify.h \
   sys/fsuid.h \
+  sys/futex.h \
   sys/inotify.h \
   sys/kd.h \
   sys/klog.h \
@@ -199,6 +204,7 @@ tests += \
   tst-epoll-ioctls \
   tst-fanotify \
   tst-fdopendir-o_path \
+  tst-futex \
   tst-getauxval \
   tst-gettid \
   tst-gettid-kill \
@@ -275,6 +281,7 @@ tests-time64 += \
   tst-adjtimex-time64 \
   tst-clock_adjtime-time64 \
   tst-epoll-time64 \
+  tst-futex-time64 \
   tst-ntp_adjtime-time64 \
   tst-ntp_gettime-time64 \
   tst-ntp_gettimex-time64 \
diff --git a/sysdeps/unix/sysv/linux/Versions b/sysdeps/unix/sysv/linux/Versions
index c7f199f13f..b417759862 100644
--- a/sysdeps/unix/sysv/linux/Versions
+++ b/sysdeps/unix/sysv/linux/Versions
@@ -343,6 +343,15 @@ libc {
     mseal;
     openat2;
   }
+  GLIBC_2.45 {
+    futex_requeue;
+%ifdef TIME64_NON_DEFAULT
+    __futex_timedwait_time64;
+%endif
+    futex_timedwait;
+    futex_wait;
+    futex_wake;
+  }
   GLIBC_PRIVATE {
     # functions used in other libraries
     __syscall_rt_sigqueueinfo;
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index 3156688add..9ac3743c8d 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2775,3 +2775,7 @@ GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.45 futex_requeue F
+GLIBC_2.45 futex_timedwait F
+GLIBC_2.45 futex_wait F
+GLIBC_2.45 futex_wake F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index 8af5b0b581..93781d00f1 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -3122,6 +3122,10 @@ GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.45 futex_requeue F
+GLIBC_2.45 futex_timedwait F
+GLIBC_2.45 futex_wait F
+GLIBC_2.45 futex_wake F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
index 35fcef2cc4..f081a512c2 100644
--- a/sysdeps/unix/sysv/linux/arc/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
@@ -2536,3 +2536,7 @@ GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.45 futex_requeue F
+GLIBC_2.45 futex_timedwait F
+GLIBC_2.45 futex_wait F
+GLIBC_2.45 futex_wake F
diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
index a6c6b951bf..43b75f779a 100644
--- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
@@ -2828,6 +2828,11 @@ GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.45 __futex_timedwait_time64 F
+GLIBC_2.45 futex_requeue F
+GLIBC_2.45 futex_timedwait F
+GLIBC_2.45 futex_wait F
+GLIBC_2.45 futex_wake F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
index e76015fe66..0dd5e4948f 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
@@ -2825,6 +2825,11 @@ GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.45 __futex_timedwait_time64 F
+GLIBC_2.45 futex_requeue F
+GLIBC_2.45 futex_timedwait F
+GLIBC_2.45 futex_wait F
+GLIBC_2.45 futex_wake F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
index 1fb7cdcad5..c7675ff2ef 100644
--- a/sysdeps/unix/sysv/linux/csky/libc.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
@@ -2812,3 +2812,8 @@ GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.45 __futex_timedwait_time64 F
+GLIBC_2.45 futex_requeue F
+GLIBC_2.45 futex_timedwait F
+GLIBC_2.45 futex_wait F
+GLIBC_2.45 futex_wake F
diff --git a/sysdeps/unix/sysv/linux/futex_requeue.c b/sysdeps/unix/sysv/linux/futex_requeue.c
new file mode 100644
index 0000000000..e0a5d944b1
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/futex_requeue.c
@@ -0,0 +1,35 @@
+/* Requeue threads waiting on a futex.  Linux implementation.
+   Copyright (C) 2026 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <sys/futex.h>
+#include <futex-internal.h>
+
+int
+futex_requeue (uint32_t *futexp, uint32_t expected, int nwake,
+	       uint32_t *targetp, int nrequeue, unsigned int flags)
+{
+  if (!__futex_check_flags (flags))
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+
+  return __futex_cmp_requeue_errno (futexp, expected, nwake, targetp,
+				    nrequeue, flags);
+}
diff --git a/sysdeps/unix/sysv/linux/futex_timedwait.c b/sysdeps/unix/sysv/linux/futex_timedwait.c
new file mode 100644
index 0000000000..65bfb842ae
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/futex_timedwait.c
@@ -0,0 +1,55 @@
+/* Wait on a futex with a timeout.  Linux implementation.
+   Copyright (C) 2026 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <time.h>
+#include <sys/futex.h>
+#include <futex-internal.h>
+
+int
+__futex_timedwait_time64 (uint32_t *futexp, uint32_t expected,
+			  clockid_t clockid,
+			  const struct __timespec64 *abstime,
+			  unsigned int flags)
+{
+  if (!__futex_check_flags (flags))
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+
+  return __futex_abstimed_wait64_errno (futexp, expected, clockid, abstime,
+					flags);
+}
+
+#if __TIMESIZE != 64
+libc_hidden_def (__futex_timedwait_time64)
+
+int
+futex_timedwait (uint32_t *futexp, uint32_t expected, clockid_t clockid,
+		 const struct timespec *abstime, unsigned int flags)
+{
+  struct __timespec64 ts64, *pts64 = NULL;
+  if (abstime != NULL)
+    {
+      ts64 = valid_timespec_to_timespec64 (*abstime);
+      pts64 = &ts64;
+    }
+  return __futex_timedwait_time64 (futexp, expected, clockid, pts64, flags);
+}
+#endif
diff --git a/sysdeps/unix/sysv/linux/futex_wait.c b/sysdeps/unix/sysv/linux/futex_wait.c
new file mode 100644
index 0000000000..dbac5ed0d2
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/futex_wait.c
@@ -0,0 +1,36 @@
+/* Wait on a futex.  Linux implementation.
+   Copyright (C) 2026 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <sys/futex.h>
+#include <futex-internal.h>
+
+int
+futex_wait (uint32_t *futexp, uint32_t expected, unsigned int flags)
+{
+  if (!__futex_check_flags (flags))
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+
+  /* A null ABSTIME blocks indefinitely, making this equivalent to a
+     plain FUTEX_WAIT.  */
+  return __futex_abstimed_wait64_errno (futexp, expected, CLOCK_MONOTONIC,
+					NULL, flags);
+}
diff --git a/sysdeps/unix/sysv/linux/futex_wake.c b/sysdeps/unix/sysv/linux/futex_wake.c
new file mode 100644
index 0000000000..1f1903e5ea
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/futex_wake.c
@@ -0,0 +1,38 @@
+/* Wake threads waiting on a futex.  Linux implementation.
+   Copyright (C) 2026 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <sys/futex.h>
+#include <futex-internal.h>
+
+int
+futex_wake (uint32_t *futexp, int count, unsigned int flags)
+{
+  int r;
+  if (__futex_check_flags (flags))
+    r = __futex_wake_internal (futexp, count, flags ^ FUTEX_PRIVATE_FLAG);
+  else
+    r = -EINVAL;
+
+  if (__glibc_unlikely (r < 0))
+    {
+      __set_errno (-r);
+      return -1;
+    }
+  return r;
+}
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 0710ccecf9..70957e8d70 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -2849,6 +2849,11 @@ GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.45 __futex_timedwait_time64 F
+GLIBC_2.45 futex_requeue F
+GLIBC_2.45 futex_timedwait F
+GLIBC_2.45 futex_wait F
+GLIBC_2.45 futex_wake F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 3afe3a88eb..0543cc2540 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -3032,6 +3032,11 @@ GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.45 __futex_timedwait_time64 F
+GLIBC_2.45 futex_requeue F
+GLIBC_2.45 futex_timedwait F
+GLIBC_2.45 futex_wait F
+GLIBC_2.45 futex_wake F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/loongarch/ilp32/libc.abilist b/sysdeps/unix/sysv/linux/loongarch/ilp32/libc.abilist
index 7c6d7055c3..74b16c137f 100644
--- a/sysdeps/unix/sysv/linux/loongarch/ilp32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/loongarch/ilp32/libc.abilist
@@ -2287,3 +2287,7 @@ GLIBC_2.44 wprintf F
 GLIBC_2.44 write F
 GLIBC_2.44 writev F
 GLIBC_2.44 wscanf F
+GLIBC_2.45 futex_requeue F
+GLIBC_2.45 futex_timedwait F
+GLIBC_2.45 futex_wait F
+GLIBC_2.45 futex_wake F
diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
index c2b3a66d3a..2962b730e8 100644
--- a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
@@ -2296,3 +2296,7 @@ GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.45 futex_requeue F
+GLIBC_2.45 futex_timedwait F
+GLIBC_2.45 futex_wait F
+GLIBC_2.45 futex_wake F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index d6855131e8..96c17703fd 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -2808,6 +2808,11 @@ GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.45 __futex_timedwait_time64 F
+GLIBC_2.45 futex_requeue F
+GLIBC_2.45 futex_timedwait F
+GLIBC_2.45 futex_wait F
+GLIBC_2.45 futex_wake F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index 4e3fe9c42f..a392bf3a3a 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -2975,6 +2975,11 @@ GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.45 __futex_timedwait_time64 F
+GLIBC_2.45 futex_requeue F
+GLIBC_2.45 futex_timedwait F
+GLIBC_2.45 futex_wait F
+GLIBC_2.45 futex_wake F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
index 29f0c5f954..1c419e0558 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
@@ -2861,3 +2861,8 @@ GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.45 __futex_timedwait_time64 F
+GLIBC_2.45 futex_requeue F
+GLIBC_2.45 futex_timedwait F
+GLIBC_2.45 futex_wait F
+GLIBC_2.45 futex_wake F
diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
index 2ef62838f7..236b0a9949 100644
--- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
@@ -2858,3 +2858,8 @@ GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.45 __futex_timedwait_time64 F
+GLIBC_2.45 futex_requeue F
+GLIBC_2.45 futex_timedwait F
+GLIBC_2.45 futex_wait F
+GLIBC_2.45 futex_wake F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index 031e8961ac..59673b7709 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -2938,6 +2938,11 @@ GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.45 __futex_timedwait_time64 F
+GLIBC_2.45 futex_requeue F
+GLIBC_2.45 futex_timedwait F
+GLIBC_2.45 futex_wait F
+GLIBC_2.45 futex_wake F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
index 8dc99d81b4..2cf11e9bd9 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -2936,6 +2936,11 @@ GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.45 __futex_timedwait_time64 F
+GLIBC_2.45 futex_requeue F
+GLIBC_2.45 futex_timedwait F
+GLIBC_2.45 futex_wait F
+GLIBC_2.45 futex_wake F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index 054c5b6391..12fcf6c276 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -2944,6 +2944,11 @@ GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.45 __futex_timedwait_time64 F
+GLIBC_2.45 futex_requeue F
+GLIBC_2.45 futex_timedwait F
+GLIBC_2.45 futex_wait F
+GLIBC_2.45 futex_wake F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index 13f0148bc0..d2056aa028 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -2846,6 +2846,10 @@ GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.45 futex_requeue F
+GLIBC_2.45 futex_timedwait F
+GLIBC_2.45 futex_wait F
+GLIBC_2.45 futex_wake F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/or1k/libc.abilist b/sysdeps/unix/sysv/linux/or1k/libc.abilist
index e7ffe07dd8..7b82f1b2c8 100644
--- a/sysdeps/unix/sysv/linux/or1k/libc.abilist
+++ b/sysdeps/unix/sysv/linux/or1k/libc.abilist
@@ -2286,3 +2286,7 @@ GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.45 futex_requeue F
+GLIBC_2.45 futex_timedwait F
+GLIBC_2.45 futex_wait F
+GLIBC_2.45 futex_wake F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index dea4b20f05..6ace1864a0 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -3165,6 +3165,11 @@ GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.45 __futex_timedwait_time64 F
+GLIBC_2.45 futex_requeue F
+GLIBC_2.45 futex_timedwait F
+GLIBC_2.45 futex_wait F
+GLIBC_2.45 futex_wake F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index b45e127463..556cb13f78 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -3210,6 +3210,11 @@ GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.45 __futex_timedwait_time64 F
+GLIBC_2.45 futex_requeue F
+GLIBC_2.45 futex_timedwait F
+GLIBC_2.45 futex_wait F
+GLIBC_2.45 futex_wake F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
index 942cf6a027..aede41f65e 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
@@ -2919,6 +2919,10 @@ GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.45 futex_requeue F
+GLIBC_2.45 futex_timedwait F
+GLIBC_2.45 futex_wait F
+GLIBC_2.45 futex_wake F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
index 65d78e5076..60ee39b40c 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
@@ -2995,3 +2995,7 @@ GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.45 futex_requeue F
+GLIBC_2.45 futex_timedwait F
+GLIBC_2.45 futex_wait F
+GLIBC_2.45 futex_wake F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
index dcab30d72e..3760aa9c2e 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
@@ -2539,3 +2539,7 @@ GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.45 futex_requeue F
+GLIBC_2.45 futex_timedwait F
+GLIBC_2.45 futex_wait F
+GLIBC_2.45 futex_wake F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index 796ef35e26..4f19643514 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2739,3 +2739,7 @@ GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.45 futex_requeue F
+GLIBC_2.45 futex_timedwait F
+GLIBC_2.45 futex_wait F
+GLIBC_2.45 futex_wake F
diff --git a/sysdeps/unix/sysv/linux/s390/libc.abilist b/sysdeps/unix/sysv/linux/s390/libc.abilist
index 8f2350ee0b..76d21db2a8 100644
--- a/sysdeps/unix/sysv/linux/s390/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/libc.abilist
@@ -2956,6 +2956,10 @@ GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.45 futex_requeue F
+GLIBC_2.45 futex_timedwait F
+GLIBC_2.45 futex_wait F
+GLIBC_2.45 futex_wake F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
index 7aa98c5aed..ff8093da80 100644
--- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
@@ -2855,6 +2855,11 @@ GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.45 __futex_timedwait_time64 F
+GLIBC_2.45 futex_requeue F
+GLIBC_2.45 futex_timedwait F
+GLIBC_2.45 futex_wait F
+GLIBC_2.45 futex_wake F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
index 6bd4f8f63a..acca32532b 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
@@ -2852,6 +2852,11 @@ GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.45 __futex_timedwait_time64 F
+GLIBC_2.45 futex_requeue F
+GLIBC_2.45 futex_timedwait F
+GLIBC_2.45 futex_wait F
+GLIBC_2.45 futex_wake F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index b52cab2a35..baa6d23a8e 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -3186,6 +3186,11 @@ GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.45 __futex_timedwait_time64 F
+GLIBC_2.45 futex_requeue F
+GLIBC_2.45 futex_timedwait F
+GLIBC_2.45 futex_wait F
+GLIBC_2.45 futex_wake F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index ff99cd4f21..4224217e0c 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -2822,6 +2822,10 @@ GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.45 futex_requeue F
+GLIBC_2.45 futex_timedwait F
+GLIBC_2.45 futex_wait F
+GLIBC_2.45 futex_wake F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/sys/futex.h b/sysdeps/unix/sysv/linux/sys/futex.h
new file mode 100644
index 0000000000..2830ae05fa
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/sys/futex.h
@@ -0,0 +1,85 @@
+/* Wrappers for the Linux futex system call.
+   Copyright (C) 2026 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#ifndef _SYS_FUTEX_H
+#define _SYS_FUTEX_H	1
+
+#include <features.h>
+#include <stdint.h>
+#include <bits/types.h>
+#include <bits/types/clockid_t.h>
+#include <bits/types/struct_timespec.h>
+
+#ifndef FUTEX_PRIVATE_FLAG
+# define FUTEX_PRIVATE_FLAG	128
+#endif
+
+__BEGIN_DECLS
+
+/* If *FUTEXP == EXPECTED block until woken by futex_wake (or spuriously).
+   Returns 0 when woken, or -1 and sets errno on failure.  */
+extern int futex_wait (uint32_t *__futexp, uint32_t __expected,
+		       unsigned int __flags)
+     __THROW __nonnull ((1));
+
+/* Like futex_wait, but do not block past the absolute timeout ABSTIME
+   measured against CLOCKID (which must be CLOCK_REALTIME or
+   CLOCK_MONOTONIC).  If ABSTIME is null, block without a timeout.  */
+#ifndef __USE_TIME64_REDIRECTS
+extern int futex_timedwait (uint32_t *__futexp, uint32_t __expected,
+			    clockid_t __clockid,
+			    const struct timespec *__abstime,
+			    unsigned int __flags)
+     __THROW __nonnull ((1));
+#else
+# ifdef __REDIRECT_NTH
+extern int __REDIRECT_NTH (futex_timedwait,
+			   (uint32_t *__futexp, uint32_t __expected,
+			    clockid_t __clockid,
+			    const struct timespec *__abstime,
+			    unsigned int __flags),
+			   __futex_timedwait_time64)
+     __nonnull ((1));
+# else
+#  define futex_timedwait __futex_timedwait_time64
+extern int futex_timedwait (uint32_t *__futexp, uint32_t __expected,
+			    clockid_t __clockid,
+			    const struct timespec *__abstime,
+			    unsigned int __flags)
+     __THROW __nonnull ((1));
+# endif
+#endif
+
+/* Wake up to COUNT threads blocked on FUTEXP (INT_MAX to wake all waiters).
+   Returns the number of woken threads (zero if no thread was blocked), or
+   -1 and sets errno on failure.  */
+extern int futex_wake (uint32_t *__futexp, int __count, unsigned int __flags)
+     __THROW __nonnull ((1));
+
+/* If *FUTEXP == EXPECTED wake up to NWAKE threads blocked on FUTEXP and
+   requeue up to NREQUEUE of the remaining blocked threads to wait on TARGETP
+   instead.  Returns the total number of woken and requeued threads, or -1
+   and sets errno on failure (EAGAIN if *FUTEXP does not match EXPECTED).  */
+extern int futex_requeue (uint32_t *__futexp, uint32_t __expected,
+			  int __nwake, uint32_t *__targetp, int __nrequeue,
+			  unsigned int __flags)
+     __THROW __nonnull ((1, 4));
+
+__END_DECLS
+
+#endif /* sys/futex.h */
diff --git a/sysdeps/unix/sysv/linux/tst-futex-time64.c b/sysdeps/unix/sysv/linux/tst-futex-time64.c
new file mode 100644
index 0000000000..d95628a273
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-futex-time64.c
@@ -0,0 +1 @@
+#include "tst-futex.c"
diff --git a/sysdeps/unix/sysv/linux/tst-futex.c b/sysdeps/unix/sysv/linux/tst-futex.c
new file mode 100644
index 0000000000..fd96aa1b5a
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-futex.c
@@ -0,0 +1,179 @@
+/* Test for futex_wait, futex_timedwait, futex_wake, and futex_requeue.
+   Copyright (C) 2026 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <limits.h>
+#include <sched.h>
+#include <stdint.h>
+#include <sys/futex.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <support/timespec.h>
+#include <support/xthread.h>
+#include <support/xtime.h>
+#include <support/xunistd.h>
+
+#define BAD_FLAGS (~FUTEX_PRIVATE_FLAG)
+
+static uint32_t ftx1;
+static uint32_t ftx2;
+
+static void *
+waiter_tf (void *closure)
+{
+  while (__atomic_load_n (&ftx1, __ATOMIC_RELAXED) == 0)
+    {
+      int r = futex_wait (&ftx1, 0, FUTEX_PRIVATE_FLAG);
+      TEST_VERIFY_EXIT (r == 0
+			|| (r == -1 && (errno == EAGAIN || errno == EINTR)));
+    }
+  return NULL;
+}
+
+static int
+do_test (void)
+{
+  uint32_t word = 5;
+
+  /* Value mismatch does not block.  */
+  TEST_COMPARE (futex_wait (&word, 4, FUTEX_PRIVATE_FLAG), -1);
+  TEST_COMPARE (errno, EAGAIN);
+  TEST_COMPARE (futex_wait (&word, 4, 0), -1);
+  TEST_COMPARE (errno, EAGAIN);
+
+  /* Waking with no waiters reports zero woken threads.  */
+  TEST_COMPARE (futex_wake (&word, INT_MAX, FUTEX_PRIVATE_FLAG), 0);
+
+  /* Invalid flags.  */
+  TEST_COMPARE (futex_wait (&word, 5, BAD_FLAGS), -1);
+  TEST_COMPARE (errno, EINVAL);
+  TEST_COMPARE (futex_wake (&word, 1, BAD_FLAGS), -1);
+  TEST_COMPARE (errno, EINVAL);
+  TEST_COMPARE (futex_requeue (&word, 5, 0, &ftx2, 1, BAD_FLAGS), -1);
+  TEST_COMPARE (errno, EINVAL);
+
+  /* Requeue with a value mismatch fails and moves no waiters.  */
+  TEST_COMPARE (futex_requeue (&ftx1, 1, 0, &ftx2, 1, FUTEX_PRIVATE_FLAG),
+		-1);
+  TEST_COMPARE (errno, EAGAIN);
+
+  /* Block a thread on FTX1, requeue it to FTX2, and wake it there.  The
+     requeue loop also synchronizes with the waiter actually entering the
+     kernel, it moves no thread (and returns 0) until the waiter is enqueued
+     on FTX1.  */
+  {
+    pthread_t thr = xpthread_create (NULL, waiter_tf, NULL);
+
+    int r;
+    while ((r = futex_requeue (&ftx1, 0, 0, &ftx2, 1, FUTEX_PRIVATE_FLAG))
+	   == 0)
+      sched_yield ();
+    TEST_COMPARE (r, 1);
+
+    /* Release the waiter loop, then wake the requeued thread on FTX2.  */
+    __atomic_store_n (&ftx1, 1, __ATOMIC_RELAXED);
+    TEST_COMPARE (futex_wake (&ftx2, INT_MAX, FUTEX_PRIVATE_FLAG), 1);
+    /* In case the waiter was woken spuriously and blocked on FTX1 again.  */
+    futex_wake (&ftx1, INT_MAX, FUTEX_PRIVATE_FLAG);
+
+    xpthread_join (thr);
+  }
+
+  /* The same wait/requeue/wake round-trip with process-shared futexes
+     (FLAGS of zero) across processes, with the futex words in a shared
+     mapping.  */
+  {
+    uint32_t *sftx = support_shared_allocate (2 * sizeof (uint32_t));
+
+    pid_t pid = xfork ();
+    if (pid == 0)
+      {
+	while (__atomic_load_n (&sftx[0], __ATOMIC_RELAXED) == 0)
+	  {
+	    int r = futex_wait (&sftx[0], 0, 0);
+	    if (r != 0 && !(r == -1 && (errno == EAGAIN || errno == EINTR)))
+	      _exit (2);
+	  }
+	_exit (0);
+      }
+
+    /* The requeue loop also synchronizes with the child actually being
+       enqueued on the shared futex.  */
+    int r;
+    while ((r = futex_requeue (&sftx[0], 0, 0, &sftx[1], 1, 0)) == 0)
+      sched_yield ();
+    TEST_COMPARE (r, 1);
+
+    __atomic_store_n (&sftx[0], 1, __ATOMIC_RELAXED);
+    TEST_COMPARE (futex_wake (&sftx[1], INT_MAX, 0), 1);
+    /* In case the child was woken spuriously and blocked again.  */
+    futex_wake (&sftx[0], INT_MAX, 0);
+
+    int status;
+    xwaitpid (pid, &status, 0);
+    TEST_VERIFY (WIFEXITED (status));
+    TEST_COMPARE (WEXITSTATUS (status), 0);
+
+    support_shared_free (sftx);
+  }
+
+  {
+    uint32_t tword = 0;
+    struct timespec ts = make_timespec (0, 0);
+
+    /* Value mismatch is checked before the timeout.  */
+    TEST_COMPARE (futex_timedwait (&word, 4, CLOCK_MONOTONIC, &ts,
+				   FUTEX_PRIVATE_FLAG), -1);
+    TEST_COMPARE (errno, EAGAIN);
+
+    /* Invalid flags and clocks.  */
+    TEST_COMPARE (futex_timedwait (&tword, 0, CLOCK_MONOTONIC, &ts,
+				   BAD_FLAGS), -1);
+    TEST_COMPARE (errno, EINVAL);
+    TEST_COMPARE (futex_timedwait (&tword, 0, CLOCK_PROCESS_CPUTIME_ID, &ts,
+				   FUTEX_PRIVATE_FLAG), -1);
+    TEST_COMPARE (errno, EINVAL);
+
+    /* Timeouts in the past, including negative tv_sec.  */
+    TEST_COMPARE (futex_timedwait (&tword, 0, CLOCK_MONOTONIC, &ts,
+				   FUTEX_PRIVATE_FLAG), -1);
+    TEST_COMPARE (errno, ETIMEDOUT);
+    ts = make_timespec (-1, 0);
+    TEST_COMPARE (futex_timedwait (&tword, 0, CLOCK_REALTIME, &ts,
+				   FUTEX_PRIVATE_FLAG), -1);
+    TEST_COMPARE (errno, ETIMEDOUT);
+
+    /* An actual short wait on both supported clocks.  */
+    for (int i = 0; i < 2; i++)
+      {
+	clockid_t clockid = i == 0 ? CLOCK_REALTIME : CLOCK_MONOTONIC;
+	struct timespec timeout
+	  = timespec_add (xclock_now (clockid), make_timespec (0, 100000000));
+	TEST_COMPARE (futex_timedwait (&tword, 0, clockid, &timeout,
+				       FUTEX_PRIVATE_FLAG), -1);
+	TEST_COMPARE (errno, ETIMEDOUT);
+	TEST_TIMESPEC_NOW_OR_AFTER (clockid, timeout);
+      }
+  }
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index 306cd627fd..8ae243e974 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2771,6 +2771,10 @@ GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.45 futex_requeue F
+GLIBC_2.45 futex_timedwait F
+GLIBC_2.45 futex_wait F
+GLIBC_2.45 futex_wake F
 GLIBC_2.5 __readlinkat_chk F
 GLIBC_2.5 inet6_opt_append F
 GLIBC_2.5 inet6_opt_find F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index 8b9c448742..c9a00be076 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2790,3 +2790,7 @@ GLIBC_2.43 memset_explicit F
 GLIBC_2.43 mseal F
 GLIBC_2.43 openat2 F
 GLIBC_2.43 umaxabs F
+GLIBC_2.45 futex_requeue F
+GLIBC_2.45 futex_timedwait F
+GLIBC_2.45 futex_wait F
+GLIBC_2.45 futex_wake F
-- 
2.53.0



More information about the Libc-alpha mailing list