@@ -1684,6 +1684,41 @@ def test_self_trace(self):
16841684 self .assertEqual (this_thread_stack [1 ].funcname , "TestGetStackTrace.test_self_trace" )
16851685 self .assertTrue (this_thread_stack [1 ].filename .endswith ("test_external_inspection.py" ))
16861686
1687+ @skip_if_not_supported
1688+ @unittest .skipIf (
1689+ sys .platform == "linux" and not PROCESS_VM_READV_SUPPORTED ,
1690+ "Test only runs on Linux with process_vm_readv support" ,
1691+ )
1692+ def test_empty_native_thread_stack (self ):
1693+ _testcapi = import_module ("_testcapi" )
1694+ lock = threading .Lock ()
1695+ lock .acquire ()
1696+ # A built-in callback leaves the C thread's Python stack empty.
1697+ _testcapi .call_in_temporary_c_thread (lock .acquire , False )
1698+ try :
1699+ for cache_frames , native in ((False , False ), (False , True ),
1700+ (True , False ), (True , True )):
1701+ with self .subTest (cache_frames = cache_frames , native = native ):
1702+ unwinder = RemoteUnwinder (
1703+ os .getpid (), all_threads = True , cache_frames = cache_frames ,
1704+ native = native ,
1705+ )
1706+ _get_stack_trace_with_retry (
1707+ unwinder , condition = lambda trace : len (trace [0 ].threads ) == 2 ,
1708+ )
1709+ threads = unwinder .get_stack_trace ()[0 ].threads
1710+ native_stack , python_stack = sorted (
1711+ (thread .frame_info for thread in threads ), key = len ,
1712+ )
1713+ self .assertEqual (native_stack , [])
1714+ self .assertEqual (
1715+ python_stack [0 ].funcname ,
1716+ "TestGetStackTrace.test_empty_native_thread_stack" ,
1717+ )
1718+ finally :
1719+ lock .release ()
1720+ _testcapi .join_temporary_c_thread ()
1721+
16871722 @skip_if_not_supported
16881723 @unittest .skipIf (
16891724 sys .platform == "linux" and not PROCESS_VM_READV_SUPPORTED ,
0 commit comments