test_set_and_clear in Lib/test/lock_tests.py starts five threads that call event.wait(), sleeps for 50 ms (wait_threads_blocked()), and then calls event.set() and event.clear(). If a thread only reaches wait() after clear(), it sees the flag unset and waits for LONG_TIMEOUT, so Bunch.__exit__ gives up after SHORT_TIMEOUT:
FAIL: test_set_and_clear (test.test_threading.EventTests.test_set_and_clear)
Traceback (most recent call last):
File "Lib/test/lock_tests.py", line 574, in test_set_and_clear
with Bunch(f, N):
File "Lib/test/lock_tests.py", line 77, in __exit__
for _ in support.sleeping_retry(support.SHORT_TIMEOUT):
...
AssertionError: timeout (30.3 seconds)
This happened in the TSan (free-threading) job of an unrelated PR, gh-158286: https://github.com/python/cpython/actions/runs/36356561195/job/108725383176
It reproduces on a free-threaded debug build with TSan (--with-thread-sanitizer --with-pydebug --disable-gil) when the test shares two CPUs with four busy-looping processes:
for i in 1 2 3 4; do taskset --cpu-list 12-13 python3 -c "while True: pass" & done
taskset --cpu-list 12-13 ./python -m test test_threading --match test_set_and_clear
The test failed in 9 of 40 runs. In a copy of the test that counts event._cond._waiters just before set(), every failure had a thread that had not yet started waiting; none was a lost wakeup.
Linked PRs
test_set_and_clearinLib/test/lock_tests.pystarts five threads that callevent.wait(), sleeps for 50 ms (wait_threads_blocked()), and then callsevent.set()andevent.clear(). If a thread only reacheswait()afterclear(), it sees the flag unset and waits forLONG_TIMEOUT, soBunch.__exit__gives up afterSHORT_TIMEOUT:This happened in the TSan (free-threading) job of an unrelated PR, gh-158286: https://github.com/python/cpython/actions/runs/36356561195/job/108725383176
It reproduces on a free-threaded debug build with TSan (
--with-thread-sanitizer --with-pydebug --disable-gil) when the test shares two CPUs with four busy-looping processes:The test failed in 9 of 40 runs. In a copy of the test that counts
event._cond._waitersjust beforeset(), every failure had a thread that had not yet started waiting; none was a lost wakeup.Linked PRs