@@ -1329,41 +1329,49 @@ def test_tlbc_cache_refresh_after_growth(self):
13291329 script = textwrap .dedent ("""\
13301330 import os, threading
13311331 from _remote_debugging import RemoteUnwinder
1332+ from _queue import SimpleQueue
13321333 from test import support
13331334
1334- go = threading.Event()
1335- stop = threading.Event()
1335+ go = threading.Lock()
1336+ stop = threading.Lock()
1337+ go.acquire()
1338+ stop.acquire()
1339+ ready = SimpleQueue()
13361340
13371341 def leaf():
1338- stop.wait()
1339-
1340- def wait_for_leaf_frames(u, expected_count):
1341- for _ in support.sleeping_retry(
1342- support.SHORT_TIMEOUT,
1343- f"Expected {expected_count} leaf frames",
1344- ):
1345- try:
1346- traces = u.get_stack_trace()
1347- except RuntimeError as exc:
1348- if str(exc) != "Failed to parse initial frame in chain":
1349- raise
1350- continue
1351- count = sum(
1352- f.funcname == "leaf"
1353- for t in traces for f in t.frame_info
1354- )
1355- if count == expected_count:
1356- return
1342+ ready.put(None)
1343+ stop.acquire()
1344+
1345+ def start_leaf():
1346+ ready.put(None)
1347+ go.acquire()
1348+ leaf()
1349+
1350+ def park():
1351+ ready.put(None)
1352+ stop.acquire()
1353+
1354+ def leaf_count(u):
1355+ return sum(
1356+ f.funcname == "leaf"
1357+ for t in u.get_stack_trace() for f in t.frame_info
1358+ )
13571359
1360+ # SimpleQueue.put() and Lock.acquire() do not push Python frames.
1361+ # Once notified, the worker's stack stays stable until go is released.
13581362 threading.Thread(target=leaf, daemon=True).start()
1363+ ready.get(timeout=support.SHORT_TIMEOUT)
13591364 for _ in range(16):
1360- threading.Thread(target=stop.wait, daemon=True).start()
1361- threading.Thread(target=lambda: (go.wait(), leaf()), daemon=True).start()
1365+ threading.Thread(target=park, daemon=True).start()
1366+ ready.get(timeout=support.SHORT_TIMEOUT)
1367+ threading.Thread(target=start_leaf, daemon=True).start()
1368+ ready.get(timeout=support.SHORT_TIMEOUT)
13621369
13631370 u = RemoteUnwinder(os.getpid(), all_threads=True)
1364- wait_for_leaf_frames(u, 1)
1365- go.set()
1366- wait_for_leaf_frames(u, 2)
1371+ assert leaf_count(u) == 1
1372+ go.release()
1373+ ready.get(timeout=support.SHORT_TIMEOUT)
1374+ assert leaf_count(u) == 2
13671375 """ )
13681376 result = subprocess .run (
13691377 [sys .executable , "-X" , "gil=0" , "-X" , "tlbc=1" , "-c" , script ],
@@ -1387,44 +1395,48 @@ def test_tlbc_cache_refresh_after_slot_fill(self):
13871395 script = textwrap .dedent ("""\
13881396 import os, threading
13891397 from _remote_debugging import RemoteUnwinder
1398+ from _queue import SimpleQueue
13901399
1391- go = threading.Event()
1392- stop = threading.Event()
1400+ go = threading.Lock()
1401+ stop = threading.Lock()
1402+ go.acquire()
1403+ stop.acquire()
1404+ ready = SimpleQueue()
13931405
13941406 def leaf():
1395- stop.wait()
1407+ ready.put(None)
1408+ stop.acquire()
1409+
1410+ def start_leaf():
1411+ ready.put(None)
1412+ go.acquire()
1413+ leaf()
13961414
13971415 from test import support
13981416
1399- def lines(u, expected_count):
1400- for _ in support.sleeping_retry(
1401- support.SHORT_TIMEOUT,
1402- f"Expected {expected_count} leaf frames",
1403- ):
1404- try:
1405- traces = u.get_stack_trace()
1406- except RuntimeError as exc:
1407- if str(exc) != "Failed to parse initial frame in chain":
1408- raise
1409- continue
1410- result = sorted(
1411- f.lineno
1412- for t in traces for f in t.frame_info
1413- if f.funcname == "leaf"
1414- )
1415- # A new frame can still point at the function definition.
1416- if (len(result) == expected_count and
1417- leaf.__code__.co_firstlineno not in result):
1418- return result
1417+ def lines(u):
1418+ return sorted(
1419+ f.lineno
1420+ for t in u.get_stack_trace() for f in t.frame_info
1421+ if f.funcname == "leaf"
1422+ )
14191423
1424+ # SimpleQueue.put() and Lock.acquire() do not push Python frames.
1425+ # Once notified, the worker's stack stays stable until go is released.
14201426 threading.Thread(target=leaf, daemon=True).start()
1421- threading.Thread(target=lambda: (go.wait(), leaf()), daemon=True).start()
1427+ ready.get(timeout=support.SHORT_TIMEOUT)
1428+ threading.Thread(target=start_leaf, daemon=True).start()
1429+ ready.get(timeout=support.SHORT_TIMEOUT)
14221430 u = RemoteUnwinder(os.getpid(), all_threads=True)
1423- before = lines(u, 1)
1424- assert before == [8], before
1425- go.set()
1426- cached = lines(u, 2)
1427- assert cached == [8, 8], cached
1431+ before = lines(u)
1432+ # The notification can be observed before put() returns, so either
1433+ # line in leaf() is a valid sample.
1434+ assert before in ([12], [13]), before
1435+ go.release()
1436+ ready.get(timeout=support.SHORT_TIMEOUT)
1437+ cached = lines(u)
1438+ assert len(cached) == 2, cached
1439+ assert all(line in (12, 13) for line in cached), cached
14281440 """ )
14291441 result = subprocess .run (
14301442 [sys .executable , "-X" , "gil=0" , "-X" , "tlbc=1" , "-c" , script ],
0 commit comments