[PATCH v3 2/3] linux: Add futex_wait, futex_timedwait, futex_wake, and futex_requeue
Adhemerval Zanella
adhemerval.zanella@linaro.org
Tue Aug 25 16:50:25 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