Skip to content

Commit 9e22078

Browse files
gh-158336: Fix race in lock_tests test_set_and_clear (#158337)
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. Co-authored-by: Victor Stinner <vstinner@python.org>
1 parent 7b1bc41 commit 9e22078

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
@@ -566,6 +566,8 @@ def test_nan_timeout(self):
566566
evt = self.eventtype()
567567
self.assertRaises(ValueError, evt.wait, float('nan'))
568568

569+
# Use private attributes (event._cond._waiters)
570+
@support.cpython_only
569571
def test_set_and_clear(self):
570572
# gh-57711: check that wait() returns true even when the event is
571573
# cleared before the waiting thread is woken up.
@@ -576,8 +578,11 @@ def f():
576578

577579
N = 5
578580
with Bunch(f, N):
579-
# Threads blocked on event.wait()
580-
wait_threads_blocked(N)
581+
# Wait until all threads are registered as waiters in
582+
# event.wait().
583+
for _ in support.sleeping_retry(support.SHORT_TIMEOUT):
584+
if len(event._cond._waiters) >= N:
585+
break
581586

582587
# Threads unblocked
583588
event.set()

0 commit comments

Comments
 (0)