FUTEX_CMP_REQUEUE(2const)
๐ FUTEX_CMP_REQUEUE ๐
okay so bestie, listen โ this is the futex op that checks a value, wakes a couple of people, and then rehomes the rest. it's giving bouncer-at-the-club energy and honestly? iconic. ๐
part of the Linux family, and this page is FUTEX_CMP_REQUEUE(2const).
๐ LIBRARY
Standard C library (libc, -lc). yeah she lives in libc, come through. โจ
๐ SYNOPSIS
#include <linux/futex.h> /* Definition of FUTEX_* constants */
#include <sys/syscall.h> /* Definition of SYS_* constants */
#include <unistd.h>
long syscall(SYS_futex, uint32_t *uaddr, FUTEX_CMP_REQUEUE,
uint32_t val, uint32_t val2, uint32_t *uaddr2,
uint32_t val3);
like yes we're raw-dogging syscall(2) because that's just how futexes are, no wrapper, no cap. ๐ซถ
โจ DESCRIPTION โจ
so the โจvibe checkโจ happens first: this operation checks whether the location uaddr still contains the value val3. if it does not, the operation fails with the error EAGAIN. no vibes, no service. ๐
otherwise? we wake up a maximum of val waiters that are waiting on the futex at uaddr. and if there are more than val waiters โ because bestie, there are always more โ then the remaining waiters get removed from the wait queue of the source futex at uaddr and added to the wait queue of the target futex at uaddr2. glow-up relocation, honestly. ๐ธ
and the val2 argument? that's the upper limit on how many waiters get requeued over to the futex at uaddr2. it's the "no more than this many, i beg" number.
now, the load from uaddr is an atomic memory access (i.e., using atomic machine instructions of the respective architecture โ she's built different at the silicon level). and this load, the comparison with val3, and the requeueing of any waiters are all performed atomically and totally ordered with respect to other operations on the same futex word. periodt. ๐
typical values to specify for val are 0 or 1. (specifying val as INT_MAX is not useful, because it would make the FUTEX_CMP_REQUEUE operation equivalent to FUTEX_WAKE(2const).) the limit value specified via val2 is typically either 1 or INT_MAX. (specifying val2 as 0 is not useful, because it would make the FUTEX_CMP_REQUEUE operation equivalent to FUTEX_WAKE(2const).)
๐ฆ the lore: why she exists
the FUTEX_CMP_REQUEUE operation was added as a replacement for the earlier FUTEX_REQUEUE(2const). the difference? the check of the value at uaddr can be used to ensure that requeueing happens only under certain conditions, which allows race conditions to be avoided in certain use cases. that's the whole upgrade bestie, and it ate. ๐
both FUTEX_REQUEUE(2const) and FUTEX_CMP_REQUEUE can be used to avoid "thundering herd" wake-ups that could occur when using FUTEX_WAKE(2const) in cases where all of the waiters that are woken need to acquire another futex. ๐ญ imagine waking everyone and they all just pile back up. tragic.
consider the following scenario, where multiple waiter threads are waiting on B, a wait queue implemented using a futex:
lock(A)
while (!check_value(V)) {
unlock(A);
block_on(B);
lock(A);
};
unlock(A);
if a waker thread used FUTEX_WAKE(2const), then all waiters waiting on B would be woken up, and they would all try to acquire lock A. however, waking all of the threads in this manner would be pointless because all except one of the threads would immediately block on lock A again. likeโฆ okay?? why did we even. ๐
by contrast, a requeue operation wakes just one waiter and moves the other waiters to lock A, and when the woken waiter unlocks A then the next waiter can proceed. efficient. orderly. main character energy. โญ
๐ RETURN VALUE
on error, -1 is returned, and errno is set to indicate the error. classic.
on success, FUTEX_CMP_REQUEUE returns the total number of waiters that were woken up or requeued to the futex for the futex word at uaddr2. and if this value is greater than val, then the difference is the number of waiters requeued to the futex for the futex word at uaddr2. math is mathing. ๐งฎ
๐ ERRORS
see futex(2).
EAGAINโ the value pointed to by uaddr is not equal to the expected value val3. (vibe check failed, sorry babe.)EFAULTโ uaddr2 did not point to a valid user-space address.EINVALโ uaddr2 does not point to a valid objectโthat is, the address is not four-byte-aligned. alignment girlies stay winning.EINVALโ the kernel detected an inconsistency between the user-space state at uaddr and the kernel stateโthat is, it detected a waiter which waits inFUTEX_LOCK_PI(2const)orFUTEX_LOCK_PI2(2const)on uaddr.
๐ณ๏ธ๐ STANDARDS
Linux. that's it, that's the line. ๐
๐ HISTORY
Linux 2.6.7. she's been around, she's vintage, she's still relevant. ๐
๐ SEE ALSO
lowkey a warning but make it cute: those EINVAL cases are real and they will find you, so double-check your alignment and your state consistency before you go blaming the kernel. ๐ซถ
mwah ๐ this page came to you courtesy of Linux man-pages 6.20, dated 2025-09-21 โ go forth and requeue responsibly, bestie. ๐โจ
๐ฆ where this page comes from
- arch rolling: man-pages 6.20-1 ยท BSD-2-Clause AND BSD-3-Clause AND BSD-4.3TAHOE AND BSD-4-Clause-UC AND GPL-1.0-or-later AND GPL-2.0-only AND GPL-2.0-or-later AND GPL-3.0-or-later AND LGPL-3.0-linking-exception AND LGPL-3.0-or-later AND LicenseRef-Public-Domain AND LicenseRef-UltraPermissive AND Linux-man-pages-1-para AND Linux-man-pages-copyleft AND Linux-man-pages-copyleft-2-para AND Linux-man-pages-copyleft-var AND MIT AND Spencer-94
- nixpkgs unstable: man-pages 6.20
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms