[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