[RFC PATCH 2/2] linux: Add futex_waitv
Adhemerval Zanella
adhemerval.zanella@linaro.org
Tue Aug 25 16:37:20 GMT 2026
Add a wrapper for the futex_waitv system call to <sys/futex.h>:
struct futex_waiter
{
uint64_t val;
uint64_t uaddr;
uint32_t flags;
uint32_t __reserved;
};
int futex_waitv (const struct futex_waiter *waiters,
unsigned int nwaiters, unsigned int flags,
clockid_t clockid, const struct timespec *abstime);
It blocks on up to FUTEX_WAITV_MAX (128) futexes at the same time
until any of them is woken. On success it returns the array index of
the woken futex; on failure it returns -1 and sets errno. The timeout
is absolute, measured against CLOCK_REALTIME or CLOCK_MONOTONIC.
The struct futex_waiter has the same layout as the kernel struct
futex_waitv and each entry carries the kernel FUTEX2_* flags. The only
extra handling is the negative absolute timeout, which the kernel
rejects with EINVAL and the wrapper reports as ETIMEDOUT.
The underlying system call only supports 64-bit time_t and so does the
wrapper.
Checked on x86_64-linux-gnu and i686-linux-gnu.
---
NEWS | 4 +
include/sys/futex.h | 5 +
manual/threads.texi | 85 +++++++-
sysdeps/unix/sysv/linux/Makefile | 13 ++
sysdeps/unix/sysv/linux/Versions | 1 +
sysdeps/unix/sysv/linux/aarch64/libc.abilist | 1 +
sysdeps/unix/sysv/linux/alpha/libc.abilist | 1 +
sysdeps/unix/sysv/linux/arc/libc.abilist | 1 +
sysdeps/unix/sysv/linux/arm/be/libc.abilist | 1 +
sysdeps/unix/sysv/linux/arm/le/libc.abilist | 1 +
sysdeps/unix/sysv/linux/csky/libc.abilist | 1 +
sysdeps/unix/sysv/linux/futex_waitv.c | 38 ++++
sysdeps/unix/sysv/linux/hppa/libc.abilist | 1 +
sysdeps/unix/sysv/linux/i386/libc.abilist | 1 +
.../sysv/linux/loongarch/ilp32/libc.abilist | 1 +
.../sysv/linux/loongarch/lp64/libc.abilist | 1 +
.../sysv/linux/m68k/coldfire/libc.abilist | 1 +
.../unix/sysv/linux/m68k/m680x0/libc.abilist | 1 +
.../sysv/linux/microblaze/be/libc.abilist | 1 +
.../sysv/linux/microblaze/le/libc.abilist | 1 +
.../sysv/linux/mips/mips32/fpu/libc.abilist | 1 +
.../sysv/linux/mips/mips32/nofpu/libc.abilist | 1 +
.../sysv/linux/mips/mips64/n32/libc.abilist | 1 +
.../sysv/linux/mips/mips64/n64/libc.abilist | 1 +
sysdeps/unix/sysv/linux/or1k/libc.abilist | 1 +
.../linux/powerpc/powerpc32/fpu/libc.abilist | 1 +
.../powerpc/powerpc32/nofpu/libc.abilist | 1 +
.../linux/powerpc/powerpc64/be/libc.abilist | 1 +
.../linux/powerpc/powerpc64/le/libc.abilist | 1 +
.../unix/sysv/linux/riscv/rv32/libc.abilist | 1 +
.../unix/sysv/linux/riscv/rv64/libc.abilist | 1 +
sysdeps/unix/sysv/linux/s390/libc.abilist | 1 +
sysdeps/unix/sysv/linux/sh/be/libc.abilist | 1 +
sysdeps/unix/sysv/linux/sh/le/libc.abilist | 1 +
.../sysv/linux/sparc/sparc32/libc.abilist | 1 +
.../sysv/linux/sparc/sparc64/libc.abilist | 1 +
sysdeps/unix/sysv/linux/sys/futex.h | 50 +++++
sysdeps/unix/sysv/linux/tst-futex-consts.py | 71 +++++++
.../unix/sysv/linux/tst-futex-waitv-time64.c | 1 +
sysdeps/unix/sysv/linux/tst-futex-waitv.c | 197 ++++++++++++++++++
.../unix/sysv/linux/x86_64/64/libc.abilist | 1 +
.../unix/sysv/linux/x86_64/x32/libc.abilist | 1 +
42 files changed, 496 insertions(+), 1 deletion(-)
create mode 100644 sysdeps/unix/sysv/linux/futex_waitv.c
create mode 100644 sysdeps/unix/sysv/linux/tst-futex-consts.py
create mode 100644 sysdeps/unix/sysv/linux/tst-futex-waitv-time64.c
create mode 100644 sysdeps/unix/sysv/linux/tst-futex-waitv.c
diff --git a/NEWS b/NEWS
index 805a71b639..eec3907c71 100644
--- a/NEWS
+++ b/NEWS
@@ -14,6 +14,10 @@ Major new features:
the futex system call and provide the blocking building block for
implementing custom synchronization primitives.
+* On Linux, the futex_waitv function has been added. It allows waiting
+ on multiple futexes at the same time, reporting the index of the woken
+ one.
+
Deprecated and removed features, and other changes affecting compatibility:
[Add deprecations, removals and changes affecting compatibility here]
diff --git a/include/sys/futex.h b/include/sys/futex.h
index 602096a738..ec19fcd042 100644
--- a/include/sys/futex.h
+++ b/include/sys/futex.h
@@ -21,6 +21,11 @@ extern int __futex_timedwait_time64 (uint32_t *futexp, uint32_t expected,
unsigned int flags)
__nonnull ((1));
libc_hidden_proto (__futex_timedwait_time64)
+extern int futex_waitv (const struct futex_waiter *waiters,
+ unsigned int nwaiters, unsigned int flags,
+ const struct __timespec64 *abstime,
+ clockid_t clockid)
+ __nonnull ((1));
# endif
# endif /* !_ISOMAC */
diff --git a/manual/threads.texi b/manual/threads.texi
index 16c716f0ab..fffd1fabb9 100644
--- a/manual/threads.texi
+++ b/manual/threads.texi
@@ -1582,7 +1582,8 @@ 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}.
+@code{FUTEX_PRIVATE_FLAG}, so the same value is used by the
+@code{futex_waitv} per-waiter flags.
@deftypefun int futex_wait (uint32_t *@var{futexp}, uint32_t @var{expected}, unsigned int @var{flags})
@standards{Linux, sys/futex.h}
@@ -1675,6 +1676,88 @@ same address, @var{nwake} or @var{nrequeue} are negative, or
@end table
@end deftypefun
+@deftp {Data Type} {struct futex_waiter}
+@standards{Linux, sys/futex.h}
+Describes one futex to wait on in a call to @code{futex_waitv}. It
+has the same layout as the kernel @code{struct futex_waitv} and the
+following members:
+
+@table @code
+@item uint64_t val
+The value the futex word is expected to contain, as for
+@code{futex_wait}.
+
+@item uint64_t uaddr
+The address of the futex word.
+
+@item uint32_t flags
+The kernel @code{FUTEX2_*} flags for this futex word:
+@code{FUTEX2_SIZE_U32}, optionally combined with @code{FUTEX2_PRIVATE}
+(equal to @code{FUTEX_PRIVATE_FLAG}) if the futex word is only used by
+threads of the calling process, @code{FUTEX2_NUMA} if the futex word
+is followed by a second 32-bit word holding the NUMA node id of the
+kernel state (with @code{FUTEX_NO_NODE} letting the kernel choose the
+node), and @code{FUTEX2_MPOL}.
+
+@item uint32_t __reserved
+Reserved for future use; must be zero.
+@end table
+@end deftp
+
+@deftypevr Macro int FUTEX_WAITV_MAX
+@standards{Linux, sys/futex.h}
+The maximum number of elements of the array passed to @code{futex_waitv},
+ currently 128.
+@end deftypevr
+
+@deftypefun int futex_waitv (const struct futex_waiter *@var{waiters}, unsigned int @var{nwaiters}, unsigned int @var{flags}, const struct timespec *@var{abstime}, clockid_t @var{clockid})
+@standards{Linux, sys/futex.h}
+@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
+Wait on all of the @var{nwaiters} futex words described by the array
+@var{waiters}, blocking until any one of them is woken (or until a
+spurious wake-up). Each futex word is checked against the expected
+value recorded in its array entry, atomically with respect to
+concurrent futex operations, as for @code{futex_wait}.
+
+The wait is bounded by the absolute time @var{abstime} measured
+against the clock @var{clockid}, which must be @code{CLOCK_REALTIME}
+or @code{CLOCK_MONOTONIC}. If @var{abstime} is a null pointer, the
+call blocks without a timeout.
+
+The @var{flags} argument is the flags argument of the underlying
+system call and is passed to the kernel unchanged; the system call
+currently supports no flags, so it must be zero.
+
+The return value is the array index of one of the woken futex words,
+or @minus{}1 with @code{errno} set to one of the following error
+codes.
+
+@table @code
+@item EAGAIN
+A futex word did not contain the value expected by its array entry at
+the time of the call.
+
+@item EINTR
+The wait was interrupted by a signal handler.
+
+@item ETIMEDOUT
+The absolute time @var{abstime} passed before any futex word was
+woken.
+
+@item EINVAL
+@var{nwaiters} is zero or greater than @code{FUTEX_WAITV_MAX}, a futex
+word is not aligned to four bytes, a @code{flags} member is not valid,
+or @var{clockid} is not a supported clock.
+
+@item ENOSYS
+The kernel does not support the @code{futex_waitv} system call, which
+was added in Linux 5.16.
+@end table
+
+This function only operates on 64-bit @code{time_t} and is only declared
+when @code{time_t} is a 64-bit type.
+@end deftypefun
+
@c FIXME these are undocumented:
@c pthread_atfork
@c pthread_attr_destroy
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
index f6c4672a07..3eab633b3b 100644
--- a/sysdeps/unix/sysv/linux/Makefile
+++ b/sysdeps/unix/sysv/linux/Makefile
@@ -77,6 +77,7 @@ sysdep_routines += \
futex_requeue \
futex_timedwait \
futex_wait \
+ futex_waitv \
futex_wake \
fxstat \
fxstat64 \
@@ -205,6 +206,7 @@ tests += \
tst-fanotify \
tst-fdopendir-o_path \
tst-futex \
+ tst-futex-waitv \
tst-getauxval \
tst-gettid \
tst-gettid-kill \
@@ -282,6 +284,7 @@ tests-time64 += \
tst-clock_adjtime-time64 \
tst-epoll-time64 \
tst-futex-time64 \
+ tst-futex-waitv-time64 \
tst-ntp_adjtime-time64 \
tst-ntp_gettime-time64 \
tst-ntp_gettimex-time64 \
@@ -390,6 +393,16 @@ $(objpfx)tst-pidfd-consts.out: ../sysdeps/unix/sysv/linux/tst-pidfd-consts.py
< /dev/null > $@ 2>&1; $(evaluate-test)
$(objpfx)tst-pidfd-consts.out: $(sysdeps-linux-python-deps)
+tests-special += \
+ $(objpfx)tst-futex-consts.out \
+ # tests-special
+$(objpfx)tst-futex-consts.out: ../sysdeps/unix/sysv/linux/tst-futex-consts.py
+ $(sysdeps-linux-python) \
+ ../sysdeps/unix/sysv/linux/tst-futex-consts.py \
+ $(sysdeps-linux-python-cc) \
+ < /dev/null > $@ 2>&1; $(evaluate-test)
+$(objpfx)tst-futex-consts.out: $(sysdeps-linux-python-deps)
+
tests-special += \
$(objpfx)tst-mount-consts.out \
# tests-special
diff --git a/sysdeps/unix/sysv/linux/Versions b/sysdeps/unix/sysv/linux/Versions
index b417759862..bd92f21d9d 100644
--- a/sysdeps/unix/sysv/linux/Versions
+++ b/sysdeps/unix/sysv/linux/Versions
@@ -350,6 +350,7 @@ libc {
%endif
futex_timedwait;
futex_wait;
+ futex_waitv;
futex_wake;
}
GLIBC_PRIVATE {
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index 9ac3743c8d..738626576c 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2778,4 +2778,5 @@ 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_waitv 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 93781d00f1..53085aa5d0 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -3125,6 +3125,7 @@ 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_waitv F
GLIBC_2.45 futex_wake F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F
diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
index f081a512c2..3bde0417c9 100644
--- a/sysdeps/unix/sysv/linux/arc/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
@@ -2539,4 +2539,5 @@ 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_waitv 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 43b75f779a..1c9c1cdc26 100644
--- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
@@ -2832,6 +2832,7 @@ 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_waitv F
GLIBC_2.45 futex_wake F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F
diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
index 0dd5e4948f..811a07e242 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
@@ -2829,6 +2829,7 @@ 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_waitv F
GLIBC_2.45 futex_wake F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F
diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
index c7675ff2ef..4280091906 100644
--- a/sysdeps/unix/sysv/linux/csky/libc.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
@@ -2816,4 +2816,5 @@ 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_waitv F
GLIBC_2.45 futex_wake F
diff --git a/sysdeps/unix/sysv/linux/futex_waitv.c b/sysdeps/unix/sysv/linux/futex_waitv.c
new file mode 100644
index 0000000000..5f0ca9057f
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/futex_waitv.c
@@ -0,0 +1,38 @@
+/* Wait on multiple futexes.
+ 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 <sysdep.h>
+
+int
+futex_waitv (const struct futex_waiter *waiters, unsigned int nwaiters,
+ unsigned int flags, const struct __timespec64 *abstime,
+ clockid_t clockid)
+{
+ int r;
+ if (__glibc_unlikely (abstime != NULL && abstime->tv_sec < 0))
+ r = -ETIMEDOUT;
+ else
+ r = INTERNAL_SYSCALL_CALL (futex_waitv, waiters, nwaiters, flags,
+ abstime, clockid);
+ return INTERNAL_SYSCALL_ERROR_P (r)
+ ? INLINE_SYSCALL_ERROR_RETURN_VALUE (-r)
+ : r;
+}
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 70957e8d70..07a11c8a05 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -2853,6 +2853,7 @@ 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_waitv F
GLIBC_2.45 futex_wake F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 0543cc2540..47d4ab3ee2 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -3036,6 +3036,7 @@ 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_waitv F
GLIBC_2.45 futex_wake F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F
diff --git a/sysdeps/unix/sysv/linux/loongarch/ilp32/libc.abilist b/sysdeps/unix/sysv/linux/loongarch/ilp32/libc.abilist
index 74b16c137f..4be7871d11 100644
--- a/sysdeps/unix/sysv/linux/loongarch/ilp32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/loongarch/ilp32/libc.abilist
@@ -2290,4 +2290,5 @@ 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_waitv 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 2962b730e8..c86486b76b 100644
--- a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
@@ -2299,4 +2299,5 @@ 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_waitv 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 96c17703fd..4bd809f238 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -2812,6 +2812,7 @@ 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_waitv F
GLIBC_2.45 futex_wake F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index a392bf3a3a..e0556e4a4f 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -2979,6 +2979,7 @@ 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_waitv F
GLIBC_2.45 futex_wake F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
index 1c419e0558..aa959e7d89 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
@@ -2865,4 +2865,5 @@ 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_waitv 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 236b0a9949..1ffb895b90 100644
--- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
@@ -2862,4 +2862,5 @@ 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_waitv 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 59673b7709..40390d67c3 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -2942,6 +2942,7 @@ 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_waitv F
GLIBC_2.45 futex_wake F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
index 2cf11e9bd9..f0b9120c7f 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -2940,6 +2940,7 @@ 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_waitv F
GLIBC_2.45 futex_wake F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index 12fcf6c276..fdd3b120a4 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -2948,6 +2948,7 @@ 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_waitv F
GLIBC_2.45 futex_wake F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index d2056aa028..cec2301f61 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -2849,6 +2849,7 @@ 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_waitv F
GLIBC_2.45 futex_wake F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F
diff --git a/sysdeps/unix/sysv/linux/or1k/libc.abilist b/sysdeps/unix/sysv/linux/or1k/libc.abilist
index 7b82f1b2c8..98bdfd38d3 100644
--- a/sysdeps/unix/sysv/linux/or1k/libc.abilist
+++ b/sysdeps/unix/sysv/linux/or1k/libc.abilist
@@ -2289,4 +2289,5 @@ 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_waitv 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 6ace1864a0..cbddfdb962 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -3169,6 +3169,7 @@ 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_waitv F
GLIBC_2.45 futex_wake F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index 556cb13f78..fd3deb9994 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -3214,6 +3214,7 @@ 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_waitv F
GLIBC_2.45 futex_wake F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
index aede41f65e..3147bba3c0 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
@@ -2922,6 +2922,7 @@ 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_waitv F
GLIBC_2.45 futex_wake F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
index 60ee39b40c..c87ef1e840 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
@@ -2998,4 +2998,5 @@ 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_waitv 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 3760aa9c2e..3ad3deb6f4 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
@@ -2542,4 +2542,5 @@ 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_waitv 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 4f19643514..bd10acb85b 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2742,4 +2742,5 @@ 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_waitv 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 76d21db2a8..657bcfa87c 100644
--- a/sysdeps/unix/sysv/linux/s390/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/libc.abilist
@@ -2959,6 +2959,7 @@ 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_waitv F
GLIBC_2.45 futex_wake F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F
diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
index ff8093da80..5a74a6108b 100644
--- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
@@ -2859,6 +2859,7 @@ 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_waitv F
GLIBC_2.45 futex_wake F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
index acca32532b..1ad6937047 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
@@ -2856,6 +2856,7 @@ 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_waitv F
GLIBC_2.45 futex_wake F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index baa6d23a8e..21e4f5f13b 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -3190,6 +3190,7 @@ 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_waitv F
GLIBC_2.45 futex_wake F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index 4224217e0c..1877ed350f 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -2825,6 +2825,7 @@ 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_waitv F
GLIBC_2.45 futex_wake F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F
diff --git a/sysdeps/unix/sysv/linux/sys/futex.h b/sysdeps/unix/sysv/linux/sys/futex.h
index 2830ae05fa..986869752f 100644
--- a/sysdeps/unix/sysv/linux/sys/futex.h
+++ b/sysdeps/unix/sysv/linux/sys/futex.h
@@ -29,6 +29,42 @@
# define FUTEX_PRIVATE_FLAG 128
#endif
+/* Maximum number of entries in the array passed to futex_waitv. */
+#define FUTEX_WAITV_MAX 128
+
+/* Per-waiter flags for futex_waitv, following the kernel definitions
+ from <linux/futex.h>. FUTEX2_PRIVATE equals FUTEX_PRIVATE_FLAG, so
+ the same value is used by all futex_* operations. */
+#ifndef FUTEX2_SIZE_U32
+# define FUTEX2_SIZE_U32 0x02
+#endif
+#ifndef FUTEX2_PRIVATE
+# define FUTEX2_PRIVATE FUTEX_PRIVATE_FLAG
+#endif
+/* With FUTEX2_NUMA the futex word is followed by a second 32-bit word
+ holding the NUMA node id of the kernel state associated with the
+ futex; FUTEX_NO_NODE there lets the kernel choose the node.
+ FUTEX2_MPOL applies the memory policy of the futex word address. */
+#ifndef FUTEX2_NUMA
+# define FUTEX2_NUMA 0x04
+#endif
+#ifndef FUTEX2_MPOL
+# define FUTEX2_MPOL 0x08
+#endif
+#ifndef FUTEX_NO_NODE
+# define FUTEX_NO_NODE (-1)
+#endif
+
+/* One futex to wait on in a futex_waitv call, with the same layout as
+ the kernel struct futex_waitv. */
+struct futex_waiter
+{
+ uint64_t val; /* Expected value of the futex word. */
+ uint64_t uaddr; /* Address of the futex word. */
+ uint32_t flags; /* FUTEX2_* flags for this futex word. */
+ uint32_t __reserved; /* Must be zero. */
+};
+
__BEGIN_DECLS
/* If *FUTEXP == EXPECTED block until woken by futex_wake (or spuriously).
@@ -80,6 +116,20 @@ extern int futex_requeue (uint32_t *__futexp, uint32_t __expected,
unsigned int __flags)
__THROW __nonnull ((1, 4));
+/* Block on all of the NWAITERS futex words described by WAITERS (at most
+ FUTEX_WAITV_MAX entries) until woken on any of them or until the absolute
+ timeout ABSTIME measured against CLOCKID (which must be CLOCK_REALTIME or
+ CLOCK_MONOTONIC) passes. If ABSTIME is null, block without a timeout.
+ Each entry checks its own expected value and carries its own FUTEX2_*
+ flags (FUTEX2_SIZE_U32, optionally with FUTEX2_PRIVATE). */
+#ifdef __USE_TIME_BITS64
+extern int futex_waitv (const struct futex_waiter *__waiters,
+ unsigned int __nwaiters, unsigned int __flags,
+ const struct timespec *__abstime,
+ clockid_t __clockid)
+ __THROW __nonnull ((1));
+#endif
+
__END_DECLS
#endif /* sys/futex.h */
diff --git a/sysdeps/unix/sysv/linux/tst-futex-consts.py b/sysdeps/unix/sysv/linux/tst-futex-consts.py
new file mode 100644
index 0000000000..aef0cf3e1b
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-futex-consts.py
@@ -0,0 +1,71 @@
+#!/usr/bin/python3
+# Test that glibc's sys/futex.h constants match the kernel's.
+# 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/>.
+
+import argparse
+import sys
+
+import glibcextract
+import glibcsyscalls
+
+
+def main():
+ """The main entry point."""
+ parser = argparse.ArgumentParser(
+ description="Test that glibc's sys/futex.h constants "
+ "match the kernel's.")
+ parser.add_argument('--cc', metavar='CC',
+ help='C compiler (including options) to use')
+ args = parser.parse_args()
+
+ if glibcextract.compile_c_snippet(
+ '#include <linux/futex.h>',
+ args.cc).returncode != 0:
+ sys.exit (77)
+
+ linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc)
+ # Constants in glibc were updated to match Linux v7.1. When glibc
+ # constants are updated this value should be updated to match the
+ # released kernel version from which the constants were taken, and
+ # the futex_waitv per-waiter flags handling should be revisited for
+ # any new FUTEX2_* flag.
+ linux_version_glibc = (7, 1)
+ def check(cte, exclude=None):
+ return glibcextract.compare_macro_consts(
+ '#include <sys/futex.h>\n',
+ '#include <linux/futex.h>\n',
+ args.cc,
+ cte,
+ exclude,
+ linux_version_glibc > linux_version_headers,
+ linux_version_headers > linux_version_glibc)
+
+ status = max(
+ check('FUTEX_WAITV_MAX'),
+ check('FUTEX_PRIVATE_FLAG'),
+ check('FUTEX_NO_NODE'),
+ # glibc only defines the FUTEX2_* flags currently accepted by
+ # the futex_waitv system call; the sizes other than 32-bit and
+ # the size mask are not provided.
+ check('FUTEX2_.*',
+ 'FUTEX2_SIZE_U8|FUTEX2_SIZE_U16|FUTEX2_SIZE_U64'
+ '|FUTEX2_SIZE_MASK'))
+ sys.exit(status)
+
+if __name__ == '__main__':
+ main()
diff --git a/sysdeps/unix/sysv/linux/tst-futex-waitv-time64.c b/sysdeps/unix/sysv/linux/tst-futex-waitv-time64.c
new file mode 100644
index 0000000000..1c1255bf17
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-futex-waitv-time64.c
@@ -0,0 +1 @@
+#include "tst-futex-waitv.c"
diff --git a/sysdeps/unix/sysv/linux/tst-futex-waitv.c b/sysdeps/unix/sysv/linux/tst-futex-waitv.c
new file mode 100644
index 0000000000..9dd14db86e
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-futex-waitv.c
@@ -0,0 +1,197 @@
+/* Test for futex_waitv.
+ 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 <stdint.h>
+#include <sys/futex.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <support/check.h>
+#include <support/test-driver.h>
+
+/* futex_waitv is only declared when time_t is a 64-bit type. */
+#ifdef __USE_TIME_BITS64
+
+# include <support/support.h>
+# include <support/timespec.h>
+# include <support/xthread.h>
+# include <support/xtime.h>
+# include <support/xunistd.h>
+
+static uint32_t ftx1;
+static uint32_t ftx2;
+static int waiter_result;
+
+static void *
+waiter_tf (void *closure)
+{
+ struct futex_waiter waiters[] =
+ {
+ { .val = 0, .uaddr = (uintptr_t) &ftx1,
+ .flags = FUTEX2_SIZE_U32 | FUTEX2_PRIVATE },
+ { .val = 0, .uaddr = (uintptr_t) &ftx2,
+ .flags = FUTEX2_SIZE_U32 | FUTEX2_PRIVATE },
+ };
+ int r;
+ do
+ r = futex_waitv (waiters, 2, 0, NULL, CLOCK_MONOTONIC);
+ while (r == -1 && errno == EINTR);
+ TEST_VERIFY (r >= 0);
+ __atomic_store_n (&waiter_result, r + 1, __ATOMIC_RELEASE);
+ return NULL;
+}
+
+static int
+do_test_futex_writev (void)
+{
+ uint32_t word = 5;
+ struct futex_waiter waiter =
+ { .val = 4,
+ .uaddr = (uintptr_t) &word,
+ .flags = FUTEX2_SIZE_U32 | FUTEX2_PRIVATE
+ };
+
+ /* Use a value mismatch to probe for kernel support (Linux 5.16). */
+ {
+ int r = futex_waitv (&waiter, 1, 0, NULL, CLOCK_MONOTONIC);
+ TEST_COMPARE (r, -1);
+ if (errno == ENOSYS)
+ FAIL_UNSUPPORTED ("kernel does not support the futex_waitv syscall");
+ TEST_COMPARE (errno, EAGAIN);
+ }
+
+ /* Nonzero syscall flags are rejected by the kernel. */
+ TEST_COMPARE (futex_waitv (&waiter, 1, ~0u, NULL, CLOCK_MONOTONIC), -1);
+ TEST_COMPARE (errno, EINVAL);
+
+ /* Invalid number of waiters and invalid per-waiter flags. */
+ TEST_COMPARE (futex_waitv (&waiter, 0, 0, NULL, CLOCK_MONOTONIC), -1);
+ TEST_COMPARE (errno, EINVAL);
+ TEST_COMPARE (futex_waitv (&waiter, FUTEX_WAITV_MAX + 1, 0, NULL,
+ CLOCK_MONOTONIC), -1);
+ TEST_COMPARE (errno, EINVAL);
+ {
+ struct futex_waiter bad =
+ { .val = 5, .uaddr = (uintptr_t) &word, .flags = ~0u };
+ TEST_COMPARE (futex_waitv (&bad, 1, 0, NULL, CLOCK_MONOTONIC), -1);
+ TEST_COMPARE (errno, EINVAL);
+ }
+
+ /* Invalid clock. */
+ {
+ struct timespec ts = make_timespec (0, 0);
+ waiter.val = 5;
+ TEST_COMPARE (futex_waitv (&waiter, 1, 0, &ts, CLOCK_PROCESS_CPUTIME_ID),
+ -1);
+ TEST_COMPARE (errno, EINVAL);
+ }
+
+ /* Timeouts in the past, including negative tv_sec. */
+ {
+ struct timespec ts = make_timespec (0, 0);
+ TEST_COMPARE (futex_waitv (&waiter, 1, 0, &ts, CLOCK_MONOTONIC), -1);
+ TEST_COMPARE (errno, ETIMEDOUT);
+ ts = make_timespec (-1, 0);
+ TEST_COMPARE (futex_waitv (&waiter, 1, 0, &ts, CLOCK_REALTIME), -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_waitv (&waiter, 1, 0, &timeout, clockid), -1);
+ TEST_COMPARE (errno, ETIMEDOUT);
+ TEST_TIMESPEC_NOW_OR_AFTER (clockid, timeout);
+ }
+
+ /* Block a thread on two futexes and wake it on the second one; the
+ return value reports the index of the woken futex. */
+ {
+ pthread_t thr = xpthread_create (NULL, waiter_tf, NULL);
+
+ while (__atomic_load_n (&waiter_result, __ATOMIC_ACQUIRE) == 0)
+ futex_wake (&ftx2, INT_MAX, FUTEX2_PRIVATE);
+ TEST_COMPARE (__atomic_load_n (&waiter_result, __ATOMIC_ACQUIRE), 1 + 1);
+
+ xpthread_join (thr);
+ }
+
+ /* The same round-trip with process-shared futexes (no FUTEX2_PRIVATE)
+ across processes, with the futex words in a shared mapping. */
+ {
+ uint32_t *sftx = support_shared_allocate (3 * sizeof (uint32_t));
+
+ pid_t pid = xfork ();
+ if (pid == 0)
+ {
+ struct futex_waiter waiters[] =
+ {
+ { .val = 0,
+ .uaddr = (uintptr_t) &sftx[0],
+ .flags = FUTEX2_SIZE_U32
+ },
+ { .val = 0,
+ .uaddr = (uintptr_t) &sftx[1],
+ .flags = FUTEX2_SIZE_U32
+ },
+ };
+ int r;
+ do
+ r = futex_waitv (waiters, 2, 0, NULL, CLOCK_MONOTONIC);
+ while (r == -1 && errno == EINTR);
+ if (r < 0)
+ _exit (2);
+ __atomic_store_n (&sftx[2], r + 1, __ATOMIC_RELEASE);
+ _exit (0);
+ }
+
+ /* Wake the child on the second shared futex. */
+ while (__atomic_load_n (&sftx[2], __ATOMIC_ACQUIRE) == 0)
+ futex_wake (&sftx[1], INT_MAX, 0);
+ TEST_COMPARE (__atomic_load_n (&sftx[2], __ATOMIC_ACQUIRE), 1 + 1);
+
+ int status;
+ xwaitpid (pid, &status, 0);
+ TEST_VERIFY (WIFEXITED (status));
+ TEST_COMPARE (WEXITSTATUS (status), 0);
+
+ support_shared_free (sftx);
+ }
+
+ return 0;
+}
+
+#endif
+
+static int
+do_test (void)
+{
+#ifdef __USE_TIME_BITS64
+ return do_test_futex_writev ();
+#else
+ FAIL_UNSUPPORTED ("futex_waitv is only declared when time_t is a "
+ "64-bit type (build with -D_TIME_BITS=64)");
+#endif
+}
+
+
+#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 8ae243e974..831583c13d 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2774,6 +2774,7 @@ 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_waitv F
GLIBC_2.45 futex_wake F
GLIBC_2.5 __readlinkat_chk F
GLIBC_2.5 inet6_opt_append F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index c9a00be076..ea5e23cf44 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2793,4 +2793,5 @@ 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_waitv F
GLIBC_2.45 futex_wake F
--
2.53.0
More information about the Libc-alpha
mailing list