[glibc/azanella/futex-wrappers] linux: Add futex_wait, futex_timedwait, futex_wake, and futex_requeue

Adhemerval Zanella via Glibc-cvs <[email protected]>
Newsgroups gmane.comp.lib.glibc.cvs
Message-ID <[email protected]>
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=57d047028b407d07bf0998b6bcda24813874d3bc

commit 57d047028b407d07bf0998b6bcda24813874d3bc
Author: Adhemerval Zanella <[email protected]>
Date:   Tue Aug 18 15:26:51 2026 -0300

    linux: Add futex_wait, futex_timedwait, futex_wake, and futex_requeue
    
    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.

Diff:
---
 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 +
 .../unix/sysv/linux/loongarch/ilp32/libc.abilist   |   4 +
 .../unix/sysv/linux/loongarch/lp64/libc.abilist    |   4 +
 sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist |   5 +
 sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist   |   5 +
 sysdeps/unix/sysv/linux/microblaze/be/libc.abilist |   5 +
 sysdeps/unix/sysv/linux/microblaze/le/libc.abilist |   5 +
 .../unix/sysv/linux/mips/mips32/fpu/libc.abilist   |   5 +
 .../unix/sysv/linux/mips/mips32/nofpu/libc.abilist |   5 +
 .../unix/sysv/linux/mips/mips64/n32/libc.abilist   |   5 +
 .../unix/sysv/linux/mips/mips64/n64/libc.abilist   |   4 +
 sysdeps/unix/sysv/linux/or1k/libc.abilist          |   4 +
 .../sysv/linux/powerpc/powerpc32/fpu/libc.abilist  |   5 +
 .../linux/powerpc/powerpc32/nofpu/libc.abilist     |   5 +
 .../sysv/linux/powerpc/powerpc64/be/libc.abilist   |   4 +
 .../sysv/linux/powerpc/powerpc64/le/libc.abilist   |   4 +
 sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist    |   4 +
 sysdeps/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 +
 sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist |   5 +
 sysdeps/unix/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 +++++++++++++++++++++
 sysdeps/unix/sysv/linux/x86_64/64/libc.abilist     |   4 +
 sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist    |   4 +
 47 files changed, 828 insertions(+), 24 deletions(-)

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 14a56d5cc3..cbe979f37a 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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.