Commit 793bdd8
authored
[libc][CndVar] reimplmement conditional variable with FIFO ordering (#192748)
This PR reimplements conditional variable with two different variants:
- futex-based shared condvar with atomic counter for waiters
- queue-based private condvar
Notice that thread-local queue node cannot be reliably accessed in
shared processes, so we cannot use a unified implementation in this
case.
POSIX.1-2024 (Issue 8) added atomicity conditions to conditional
variable:
- The `pthread_cond_broadcast()` function shall, **as a single atomic
operation**, determine which threads, if any, are blocked on the
specified condition variable cond and unblock all of these threads.
- The `pthread_cond_signal()` function shall, as a **single atomic
operation**, determine which threads, if any, are blocked on the
specified condition variable cond and unblock at least one of these
threads.
This means that threads parked after a condvar signal event shall not
steal signals before it. From my read, both implementation fulfills the
requirement but glibc claims that single futex does not provide the
stronger ordering needed by its users hence switched to a rotational
queue, to fulfill the requirements mentioned in
https://sourceware.org/bugzilla/show_bug.cgi?id=13165. As in a single
futex, the lock acquisition do not happen in order and hence when a
spurious wakeup happen, later waiters may "steal" the signal. However
musl's shared implementation and bionic's whole implementation and
Rust's std condvar still stick to a signal-futex+accounting data style.
Musl's private condvar and this implementation are even stronger in the
sense that not only the queue is decided as an atomic event, the mutex
acquisition also happens in baton-passing style.
Our implementation is different from musl in the sense that we have done
some spin attempts instead of always do futex syscall to requeue threads
(with a new requeued state added). This gives a chance for the
signal/waiter to stay in fast path if the queue is really small. Based
on the microbenchmark, this implementation is generally more performant.
We also abuse the `RawMutex`'s LOCKED state as "waiting for its turn".
One caveat we can see from the benchmark
(https://github.com/SchrodingerZhu/condvar-benchmark) is that strict
FIFO condvar is not that good if users are maintain the order on
themselves as in `turn_ring`, because many threads may just wake up
first only see it is not its turn while blocking the real thread in
turn. However, a semaphore or other synchronization primitives would be
more suitable in those cases. Even though in benchmark like
`turn_ring/broadcast_stress` made this code perform badly (but still
similar to musl anyway), they are not really the correct usage. In other
cases, we are always close to the fastest while providing a stronger
FIFO semantic.
TODO in future commit:
- support pthread cancellation. Ideally we should block cancellation
when signal is consumed and add cancellation callback for checking
illegibility.
- think about stronger ordering semantic in shared case (?)1 parent ccc608f commit 793bdd8
19 files changed
Lines changed: 523 additions & 189 deletions
File tree
- libc
- cmake/modules
- include/llvm-libc-types
- src
- __support/threads
- linux
- threads/linux
- test/integration/src
- __support/threads
- pthread
- threads
- utils/bazel/llvm-project-overlay/libc
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
154 | 154 | | |
155 | 155 | | |
156 | 156 | | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
157 | 161 | | |
158 | 162 | | |
159 | 163 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
15 | 15 | | |
16 | 16 | | |
17 | 17 | | |
| 18 | + | |
18 | 19 | | |
19 | 20 | | |
20 | 21 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
38 | 38 | | |
39 | 39 | | |
40 | 40 | | |
41 | | - | |
42 | | - | |
43 | 41 | | |
44 | 42 | | |
45 | 43 | | |
| |||
55 | 53 | | |
56 | 54 | | |
57 | 55 | | |
58 | | - | |
59 | 56 | | |
60 | 57 | | |
61 | 58 | | |
| |||
147 | 144 | | |
148 | 145 | | |
149 | 146 | | |
150 | | - | |
151 | | - | |
| 147 | + | |
| 148 | + | |
152 | 149 | | |
153 | | - | |
| 150 | + | |
| 151 | + | |
154 | 152 | | |
155 | | - | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
156 | 165 | | |
157 | 166 | | |
158 | 167 | | |
| |||
0 commit comments