@@ -1666,6 +1666,39 @@ def test_self_trace(self):
16661666 self .assertEqual (this_thread_stack [1 ].funcname , "TestGetStackTrace.test_self_trace" )
16671667 self .assertTrue (this_thread_stack [1 ].filename .endswith ("test_external_inspection.py" ))
16681668
1669+ @skip_if_not_supported
1670+ @unittest .skipIf (
1671+ sys .platform == "linux" and not PROCESS_VM_READV_SUPPORTED ,
1672+ "Test only runs on Linux with process_vm_readv support" ,
1673+ )
1674+ def test_empty_native_thread_stack (self ):
1675+ _testcapi = import_module ("_testcapi" )
1676+ lock = threading .Lock ()
1677+ lock .acquire ()
1678+ # A built-in callback leaves the C thread's Python stack empty.
1679+ _testcapi .call_in_temporary_c_thread (lock .acquire , False )
1680+ try :
1681+ for cache_frames in (False , True ):
1682+ with self .subTest (cache_frames = cache_frames ):
1683+ unwinder = RemoteUnwinder (
1684+ os .getpid (), all_threads = True , cache_frames = cache_frames ,
1685+ )
1686+ _get_stack_trace_with_retry (
1687+ unwinder , condition = lambda trace : len (trace [0 ].threads ) == 2 ,
1688+ )
1689+ threads = unwinder .get_stack_trace ()[0 ].threads
1690+ native_stack , python_stack = sorted (
1691+ (thread .frame_info for thread in threads ), key = len ,
1692+ )
1693+ self .assertEqual (native_stack , [])
1694+ self .assertEqual (
1695+ python_stack [0 ].funcname ,
1696+ "TestGetStackTrace.test_empty_native_thread_stack" ,
1697+ )
1698+ finally :
1699+ lock .release ()
1700+ _testcapi .join_temporary_c_thread ()
1701+
16691702 @skip_if_not_supported
16701703 @unittest .skipIf (
16711704 sys .platform == "linux" and not PROCESS_VM_READV_SUPPORTED ,
0 commit comments