Commit 9389af0
committed
RFC: run_loop: yield while waiting for in-flight tasks
The run loop drains queued work after finish() has been requested and also
waits for __task_count_ to reach zero. If the queue becomes empty while the
count is still non-zero, the current implementation busy-spins by repeatedly
calling __execute_all().
This can starve another thread that still needs to make progress in order to
decrement __task_count_. One concrete sequence is finish() incrementing the
count by two, setting __finishing_, and queueing the noop task. The worker can
then execute the noop, leaving the count at one, and immediately enter the
tight drain loop. The caller still needs to execute its final fetch_sub() to
bring the count to zero, but an unfair scheduler may keep running the spinning
worker instead.
This was reproducible under Valgrind's default scheduler as an intermittent
hang during run_loop shutdown. Using Valgrind's fair scheduler avoided the
hang, which pointed at a forward-progress issue rather than missing work.
Yielding when there is no queued work but tasks are still in flight allows the
thread responsible for completing those tasks to run.
With this change, the reproducer completed 700 consecutive runs under
Valgrind without --fair-sched=yes.
Co-Authored-By: GPT 5.6 Sol
Signed-off-by: Alexander Hansen <alexander.hansen@9elements.com>1 parent 15936e4 commit 9389af0
1 file changed
Lines changed: 15 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
69 | 69 | | |
70 | 70 | | |
71 | 71 | | |
72 | | - | |
73 | | - | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
74 | 87 | | |
75 | 88 | | |
76 | 89 | | |
| |||
0 commit comments