[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