https://github.com/python/cpython/commit/9e220787624afba3e20f0067da6dee3e50fcc008
commit: 9e220787624afba3e20f0067da6dee3e50fcc008
branch: main
author: Matthias Görgens <[email protected]>
committer: vstinner <[email protected]>
date: 2026-11-09T15:58:50Z
summary:

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 <[email protected]>

files:
M Lib/test/lock_tests.py

diff --git a/Lib/test/lock_tests.py b/Lib/test/lock_tests.py
index 47025c041daf1e..043bcf8f1c1aa3 100644
--- a/Lib/test/lock_tests.py
+++ b/Lib/test/lock_tests.py
@@ -566,6 +566,8 @@ def test_nan_timeout(self):
         evt = self.eventtype()
         self.assertRaises(ValueError, evt.wait, float('nan'))
 
+    # Use private attributes (event._cond._waiters)
+    @support.cpython_only
     def test_set_and_clear(self):
         # gh-57711: check that wait() returns true even when the event is
         # cleared before the waiting thread is woken up.
@@ -576,8 +578,11 @@ def f():
 
         N = 5
         with Bunch(f, N):
-            # Threads blocked on event.wait()
-            wait_threads_blocked(N)
+            # Wait until all threads are registered as waiters in
+            # event.wait().
+            for _ in support.sleeping_retry(support.SHORT_TIMEOUT):
+                if len(event._cond._waiters) >= N:
+                    break
 
             # Threads unblocked
             event.set()

_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]

Reply via email to