Я не договорила.
Я упоминал WaitForMultipleObjects() в NT. Естественно, с фьютексом, который абсолютный примитив, его семантику повторить не так просто. Что, в целом, не то, чтобы кого-то ебало в программировании под Линукс. Но ебало контрибьюторов Wine, потому что без нормального способа эмулировать поведение перф местами был в жопе.
Поэтому в Линуксе с 5.14 по 5.16 зашелестел ветер перемен. Изначально был гигантский пропозал с кучей нововведений, включая variable-sized futex word. Но решили сделать проще и адаптировать ключевые моменты под существующее ABI. А что не смогли, то в отдельные семейства сисколлов унесли. Правда, шрамы древних споведаний всё равно остались:
FUTEX2_SIZE_U8
FUTEX2_SIZE_U16
FUTEX2_SIZE_U64
These are defined, but not supported (EINVAL).
По итогу, futex2 так и остался наречием, эгидой. Но под этой эгидой добавили FUTEX_WAIT_PI2, который от обычного (не 2) отличался только лишним аргументом - теперь таймер явно указывается. До этого правда делалось то же самое, методом включения битфлага в случае, если реалтайм захотелось. Честно говоря, и сам не ведаю, на кой хуй они это сделали.
Однако!
Винишко своё таки пролоббировало, и в конце концов добавили один, но самый важный сисколл - futex_waitv. Теперь можно спать не на одном фьютексе, а сразу на куче аж до 128 штук. Воистину перемога!
Собственно, именно об этом и кричали в 2021 "ЛИНУКС ГЕЙ МИНГ ПОДНИМАЕТСЯ С КОЛЕН!!"
А, и помните ещё, я говорил, что чтобы поток заснул, нужно, чтобы val в сисколле соответствовал тому, что стоит за *uaddr? Если кому-то не похуй, то вот зачем:
If the futex value does not match val, then the call fails immediately with the error EAGAIN.
The purpose of the comparison with the expected value is to prevent lost wake-ups. If another thread changed the value of the futex word after the calling thread decided to block based on the prior value, and if the other thread executed a FUTEX_WAKE operation (or similar wake-up) after the value change and before this FUTEX_WAIT operation, then the calling thread will observe the value change and will not start to sleep.
Поэтому вокруг фьютекса всегда надо ставить гарды от EAGAIN. В сниппете с мьютексом эту роль на себя взял do..while.