@@ -2363,42 +2363,50 @@ def test_tlbc_cache_refresh_after_growth(self):
23632363 script = textwrap .dedent ("""\
23642364 import os, threading
23652365 from _remote_debugging import RemoteUnwinder
2366+ from _queue import SimpleQueue
23662367 from test import support
23672368
2368- go = threading.Event()
2369- stop = threading.Event()
2369+ go = threading.Lock()
2370+ stop = threading.Lock()
2371+ go.acquire()
2372+ stop.acquire()
2373+ ready = SimpleQueue()
23702374
23712375 def leaf():
2372- stop.wait()
2373-
2374- def wait_for_leaf_frames(u, expected_count):
2375- for _ in support.sleeping_retry(
2376- support.SHORT_TIMEOUT,
2377- f"Expected {expected_count} leaf frames",
2378- ):
2379- try:
2380- traces = u.get_stack_trace()
2381- except RuntimeError as exc:
2382- if str(exc) != "Failed to parse initial frame in chain":
2383- raise
2384- continue
2385- count = sum(
2386- f.funcname == "leaf"
2387- for i in traces
2388- for t in i.threads for f in t.frame_info
2389- )
2390- if count == expected_count:
2391- return
2376+ ready.put(None)
2377+ stop.acquire()
2378+
2379+ def start_leaf():
2380+ ready.put(None)
2381+ go.acquire()
2382+ leaf()
2383+
2384+ def park():
2385+ ready.put(None)
2386+ stop.acquire()
2387+
2388+ def leaf_count(u):
2389+ return sum(
2390+ f.funcname == "leaf"
2391+ for i in u.get_stack_trace()
2392+ for t in i.threads for f in t.frame_info
2393+ )
23922394
2395+ # SimpleQueue.put() and Lock.acquire() do not push Python frames.
2396+ # Once notified, the worker's stack stays stable until go is released.
23932397 threading.Thread(target=leaf, daemon=True).start()
2398+ ready.get(timeout=support.SHORT_TIMEOUT)
23942399 for _ in range(16):
2395- threading.Thread(target=stop.wait, daemon=True).start()
2396- threading.Thread(target=lambda: (go.wait(), leaf()), daemon=True).start()
2400+ threading.Thread(target=park, daemon=True).start()
2401+ ready.get(timeout=support.SHORT_TIMEOUT)
2402+ threading.Thread(target=start_leaf, daemon=True).start()
2403+ ready.get(timeout=support.SHORT_TIMEOUT)
23972404
23982405 u = RemoteUnwinder(os.getpid(), all_threads=True, cache_frames=False)
2399- wait_for_leaf_frames(u, 1)
2400- go.set()
2401- wait_for_leaf_frames(u, 2)
2406+ assert leaf_count(u) == 1
2407+ go.release()
2408+ ready.get(timeout=support.SHORT_TIMEOUT)
2409+ assert leaf_count(u) == 2
24022410 """ )
24032411 result = subprocess .run (
24042412 [sys .executable , "-X" , "gil=0" , "-X" , "tlbc=1" , "-c" , script ],
@@ -2422,45 +2430,49 @@ def test_tlbc_cache_refresh_after_slot_fill(self):
24222430 script = textwrap .dedent ("""\
24232431 import os, threading
24242432 from _remote_debugging import RemoteUnwinder
2433+ from _queue import SimpleQueue
24252434
2426- go = threading.Event()
2427- stop = threading.Event()
2435+ go = threading.Lock()
2436+ stop = threading.Lock()
2437+ go.acquire()
2438+ stop.acquire()
2439+ ready = SimpleQueue()
24282440
24292441 def leaf():
2430- stop.wait()
2442+ ready.put(None)
2443+ stop.acquire()
2444+
2445+ def start_leaf():
2446+ ready.put(None)
2447+ go.acquire()
2448+ leaf()
24312449
24322450 from test import support
24332451
2434- def lines(u, expected_count):
2435- for _ in support.sleeping_retry(
2436- support.SHORT_TIMEOUT,
2437- f"Expected {expected_count} leaf frames",
2438- ):
2439- try:
2440- traces = u.get_stack_trace()
2441- except RuntimeError as exc:
2442- if str(exc) != "Failed to parse initial frame in chain":
2443- raise
2444- continue
2445- result = sorted(
2446- f.location.lineno
2447- for i in traces
2448- for t in i.threads for f in t.frame_info
2449- if f.funcname == "leaf"
2450- )
2451- # A new frame can still point at the function definition.
2452- if (len(result) == expected_count and
2453- leaf.__code__.co_firstlineno not in result):
2454- return result
2452+ def lines(u):
2453+ return sorted(
2454+ f.location.lineno
2455+ for i in u.get_stack_trace()
2456+ for t in i.threads for f in t.frame_info
2457+ if f.funcname == "leaf"
2458+ )
24552459
2460+ # SimpleQueue.put() and Lock.acquire() do not push Python frames.
2461+ # Once notified, the worker's stack stays stable until go is released.
24562462 threading.Thread(target=leaf, daemon=True).start()
2457- threading.Thread(target=lambda: (go.wait(), leaf()), daemon=True).start()
2463+ ready.get(timeout=support.SHORT_TIMEOUT)
2464+ threading.Thread(target=start_leaf, daemon=True).start()
2465+ ready.get(timeout=support.SHORT_TIMEOUT)
24582466 u = RemoteUnwinder(os.getpid(), all_threads=True, cache_frames=False)
2459- before = lines(u, 1)
2460- assert before == [8], before
2461- go.set()
2462- cached = lines(u, 2)
2463- assert cached == [8, 8], cached
2467+ before = lines(u)
2468+ # The notification can be observed before put() returns, so either
2469+ # line in leaf() is a valid sample.
2470+ assert before in ([12], [13]), before
2471+ go.release()
2472+ ready.get(timeout=support.SHORT_TIMEOUT)
2473+ cached = lines(u)
2474+ assert len(cached) == 2, cached
2475+ assert all(line in (12, 13) for line in cached), cached
24642476 """ )
24652477 result = subprocess .run (
24662478 [sys .executable , "-X" , "gil=0" , "-X" , "tlbc=1" , "-c" , script ],
0 commit comments