https://github.com/python/cpython/commit/2012d35281f2f2004dd37f10f49eb56688a60e98
commit: 2012d35281f2f2004dd37f10f49eb56688a60e98
branch: 3.14
author: Miss Islington (bot) <[email protected]>
committer: vstinner <[email protected]>
date: 2026-11-09T16:34:30Z
summary:

[3.14] gh-158336: Fix race in lock_tests test_set_and_clear (GH-158337) 
(#161683)

gh-158336: Fix race in lock_tests test_set_and_clear (GH-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.
(cherry picked from commit 9e220787624afba3e20f0067da6dee3e50fcc008)

Co-authored-by: Matthias Görgens <[email protected]>
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 1a41fd3f1ddb4d..fc035abf158cda 100644
--- a/Lib/test/lock_tests.py
+++ b/Lib/test/lock_tests.py
@@ -561,6 +561,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.
@@ -571,8 +573,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