@@ -2437,42 +2437,50 @@ def test_tlbc_cache_refresh_after_growth(self):
24372437 script = textwrap .dedent ("""\
24382438 import os, threading
24392439 from _remote_debugging import RemoteUnwinder
2440+ from _queue import SimpleQueue
24402441 from test import support
24412442
2442- go = threading.Event()
2443- stop = threading.Event()
2443+ go = threading.Lock()
2444+ stop = threading.Lock()
2445+ go.acquire()
2446+ stop.acquire()
2447+ ready = SimpleQueue()
24442448
24452449 def leaf():
2446- stop.wait()
2447-
2448- def wait_for_leaf_frames(u, expected_count):
2449- for _ in support.sleeping_retry(
2450- support.SHORT_TIMEOUT,
2451- f"Expected {expected_count} leaf frames",
2452- ):
2453- try:
2454- traces = u.get_stack_trace()
2455- except RuntimeError as exc:
2456- if str(exc) != "Failed to parse initial frame in chain":
2457- raise
2458- continue
2459- count = sum(
2460- f.funcname == "leaf"
2461- for i in traces
2462- for t in i.threads for f in t.frame_info
2463- )
2464- if count == expected_count:
2465- return
2450+ ready.put(None)
2451+ stop.acquire()
2452+
2453+ def start_leaf():
2454+ ready.put(None)
2455+ go.acquire()
2456+ leaf()
2457+
2458+ def park():
2459+ ready.put(None)
2460+ stop.acquire()
2461+
2462+ def leaf_count(u):
2463+ return sum(
2464+ f.funcname == "leaf"
2465+ for i in u.get_stack_trace()
2466+ for t in i.threads for f in t.frame_info
2467+ )
24662468
2469+ # SimpleQueue.put() and Lock.acquire() do not push Python frames.
2470+ # Once notified, the worker's stack stays stable until go is released.
24672471 threading.Thread(target=leaf, daemon=True).start()
2472+ ready.get(timeout=support.SHORT_TIMEOUT)
24682473 for _ in range(16):
2469- threading.Thread(target=stop.wait, daemon=True).start()
2470- threading.Thread(target=lambda: (go.wait(), leaf()), daemon=True).start()
2474+ threading.Thread(target=park, daemon=True).start()
2475+ ready.get(timeout=support.SHORT_TIMEOUT)
2476+ threading.Thread(target=start_leaf, daemon=True).start()
2477+ ready.get(timeout=support.SHORT_TIMEOUT)
24712478
24722479 u = RemoteUnwinder(os.getpid(), all_threads=True, cache_frames=False)
2473- wait_for_leaf_frames(u, 1)
2474- go.set()
2475- wait_for_leaf_frames(u, 2)
2480+ assert leaf_count(u) == 1
2481+ go.release()
2482+ ready.get(timeout=support.SHORT_TIMEOUT)
2483+ assert leaf_count(u) == 2
24762484 """ )
24772485 result = subprocess .run (
24782486 [sys .executable , "-X" , "gil=0" , "-X" , "tlbc=1" , "-c" , script ],
@@ -2496,45 +2504,49 @@ def test_tlbc_cache_refresh_after_slot_fill(self):
24962504 script = textwrap .dedent ("""\
24972505 import os, threading
24982506 from _remote_debugging import RemoteUnwinder
2507+ from _queue import SimpleQueue
24992508
2500- go = threading.Event()
2501- stop = threading.Event()
2509+ go = threading.Lock()
2510+ stop = threading.Lock()
2511+ go.acquire()
2512+ stop.acquire()
2513+ ready = SimpleQueue()
25022514
25032515 def leaf():
2504- stop.wait()
2516+ ready.put(None)
2517+ stop.acquire()
2518+
2519+ def start_leaf():
2520+ ready.put(None)
2521+ go.acquire()
2522+ leaf()
25052523
25062524 from test import support
25072525
2508- def lines(u, expected_count):
2509- for _ in support.sleeping_retry(
2510- support.SHORT_TIMEOUT,
2511- f"Expected {expected_count} leaf frames",
2512- ):
2513- try:
2514- traces = u.get_stack_trace()
2515- except RuntimeError as exc:
2516- if str(exc) != "Failed to parse initial frame in chain":
2517- raise
2518- continue
2519- result = sorted(
2520- f.location.lineno
2521- for i in traces
2522- for t in i.threads for f in t.frame_info
2523- if f.funcname == "leaf"
2524- )
2525- # A new frame can still point at the function definition.
2526- if (len(result) == expected_count and
2527- leaf.__code__.co_firstlineno not in result):
2528- return result
2526+ def lines(u):
2527+ return sorted(
2528+ f.location.lineno
2529+ for i in u.get_stack_trace()
2530+ for t in i.threads for f in t.frame_info
2531+ if f.funcname == "leaf"
2532+ )
25292533
2534+ # SimpleQueue.put() and Lock.acquire() do not push Python frames.
2535+ # Once notified, the worker's stack stays stable until go is released.
25302536 threading.Thread(target=leaf, daemon=True).start()
2531- threading.Thread(target=lambda: (go.wait(), leaf()), daemon=True).start()
2537+ ready.get(timeout=support.SHORT_TIMEOUT)
2538+ threading.Thread(target=start_leaf, daemon=True).start()
2539+ ready.get(timeout=support.SHORT_TIMEOUT)
25322540 u = RemoteUnwinder(os.getpid(), all_threads=True, cache_frames=False)
2533- before = lines(u, 1)
2534- assert before == [8], before
2535- go.set()
2536- cached = lines(u, 2)
2537- assert cached == [8, 8], cached
2541+ before = lines(u)
2542+ # The notification can be observed before put() returns, so either
2543+ # line in leaf() is a valid sample.
2544+ assert before in ([12], [13]), before
2545+ go.release()
2546+ ready.get(timeout=support.SHORT_TIMEOUT)
2547+ cached = lines(u)
2548+ assert len(cached) == 2, cached
2549+ assert all(line in (12, 13) for line in cached), cached
25382550 """ )
25392551 result = subprocess .run (
25402552 [sys .executable , "-X" , "gil=0" , "-X" , "tlbc=1" , "-c" , script ],
0 commit comments