Skip to content

Commit 146eedb

Browse files
gh-158336: Fix race in lock_tests test_set_and_clear
test_set_and_clear started N threads calling event.wait() and then slept 50 ms (wait_threads_blocked) before calling event.set() and event.clear(). If a thread only reached wait() after clear(), it saw the flag unset and blocked for LONG_TIMEOUT, and Bunch.__exit__ gave up after SHORT_TIMEOUT. This happened on CI in the TSan free-threading job. Wait until all N threads are in the Condition's waiter list instead. Condition.wait() appends the waiter while holding the lock, and notify_all() releases every waiter in the list, so each of those threads is guaranteed to be woken by set(). On a TSan free-threading debug build, pinned to 2 CPUs shared with 4 busy-looping processes, the test failed in 9 of 40 runs before this change and 0 of 40 after.
1 parent 7352b6a commit 146eedb

1 file changed

Lines changed: 7 additions & 2 deletions

File tree

‎Lib/test/lock_tests.py‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -572,8 +572,13 @@ def f():
572572

573573
N = 5
574574
with Bunch(f, N):
575-
# Threads blocked on event.wait()
576-
wait_threads_blocked(N)
575+
# Wait until all threads are registered as waiters in
576+
# event.wait(). A thread that only reaches wait() after set()
577+
# and clear() would block until the timeout, so a fixed sleep
578+
# is not enough on a busy machine.
579+
for _ in support.sleeping_retry(support.SHORT_TIMEOUT):
580+
if len(event._cond._waiters) >= N:
581+
break
577582

578583
# Threads unblocked
579584
event.set()

0 commit comments

Comments
 (0)