@@ -2235,6 +2235,113 @@ def get_trace_with_opcodes(pid):
22352235 location .col_offset , location .end_col_offset )
22362236 self .assertIn (actual , valid_locations )
22372237
2238+ @skip_if_not_supported
2239+ @unittest .skipIf (sys ._is_gil_enabled (), "Requires free-threading" )
2240+ @unittest .skipIf (
2241+ sys .platform == "linux" and not PROCESS_VM_READV_SUPPORTED ,
2242+ "Requires process_vm_readv" ,
2243+ )
2244+ def test_tlbc_cache_refresh_after_growth (self ):
2245+ # Reproducer from gh-157660.
2246+ script = textwrap .dedent ("""\
2247+ import os, threading
2248+ from _remote_debugging import RemoteUnwinder
2249+ from test import support
2250+
2251+ go = threading.Event()
2252+ stop = threading.Event()
2253+
2254+ def leaf():
2255+ stop.wait()
2256+
2257+ def wait_for_leaf_frames(u, expected_count):
2258+ for _ in support.sleeping_retry(
2259+ support.SHORT_TIMEOUT,
2260+ f"Expected {expected_count} leaf frames",
2261+ ):
2262+ count = sum(
2263+ f.funcname == "leaf"
2264+ for i in u.get_stack_trace()
2265+ for t in i.threads for f in t.frame_info
2266+ )
2267+ if count == expected_count:
2268+ return
2269+
2270+ threading.Thread(target=leaf, daemon=True).start()
2271+ for _ in range(16):
2272+ threading.Thread(target=stop.wait, daemon=True).start()
2273+ threading.Thread(target=lambda: (go.wait(), leaf()), daemon=True).start()
2274+
2275+ u = RemoteUnwinder(os.getpid(), all_threads=True, cache_frames=False)
2276+ wait_for_leaf_frames(u, 1)
2277+ go.set()
2278+ wait_for_leaf_frames(u, 2)
2279+ """ )
2280+ result = subprocess .run (
2281+ [sys .executable , "-X" , "gil=0" , "-X" , "tlbc=1" , "-c" , script ],
2282+ capture_output = True ,
2283+ text = True ,
2284+ timeout = SHORT_TIMEOUT ,
2285+ )
2286+ self .assertEqual (
2287+ result .returncode , 0 ,
2288+ f"stdout: { result .stdout } \n stderr: { result .stderr } " ,
2289+ )
2290+
2291+ @skip_if_not_supported
2292+ @unittest .skipIf (sys ._is_gil_enabled (), "Requires free-threading" )
2293+ @unittest .skipIf (
2294+ sys .platform == "linux" and not PROCESS_VM_READV_SUPPORTED ,
2295+ "Requires process_vm_readv" ,
2296+ )
2297+ def test_tlbc_cache_refresh_after_slot_fill (self ):
2298+ # Reproducer from gh-157660.
2299+ script = textwrap .dedent ("""\
2300+ import os, threading
2301+ from _remote_debugging import RemoteUnwinder
2302+
2303+ go = threading.Event()
2304+ stop = threading.Event()
2305+
2306+ def leaf():
2307+ stop.wait()
2308+
2309+ from test import support
2310+
2311+ def lines(u, expected_count):
2312+ for _ in support.sleeping_retry(
2313+ support.SHORT_TIMEOUT,
2314+ f"Expected {expected_count} leaf frames",
2315+ ):
2316+ result = sorted(
2317+ f.location.lineno
2318+ for i in u.get_stack_trace()
2319+ for t in i.threads for f in t.frame_info
2320+ if f.funcname == "leaf"
2321+ )
2322+ if len(result) == expected_count:
2323+ return result
2324+
2325+ threading.Thread(target=leaf, daemon=True).start()
2326+ threading.Thread(target=lambda: (go.wait(), leaf()), daemon=True).start()
2327+ u = RemoteUnwinder(os.getpid(), all_threads=True, cache_frames=False)
2328+ before = lines(u, 1)
2329+ assert before == [8], before
2330+ go.set()
2331+ cached = lines(u, 2)
2332+ assert cached == [8, 8], cached
2333+ """ )
2334+ result = subprocess .run (
2335+ [sys .executable , "-X" , "gil=0" , "-X" , "tlbc=1" , "-c" , script ],
2336+ capture_output = True ,
2337+ text = True ,
2338+ timeout = SHORT_TIMEOUT ,
2339+ )
2340+ self .assertEqual (
2341+ result .returncode , 0 ,
2342+ f"stdout: { result .stdout } \n stderr: { result .stderr } " ,
2343+ )
2344+
22382345
22392346class TestUnsupportedPlatformHandling (unittest .TestCase ):
22402347 @unittest .skipIf (
0 commit comments