@@ -293,62 +293,6 @@ typedef struct {
293293 unsigned int :24 ;
294294} _thread_status ;
295295
296- static int
297- has_bound_stack (RemoteUnwinderObject * unwinder , long tid )
298- {
299- uintptr_t interp , tstate ;
300- int remaining = 8192 ;
301- if (read_ptr (unwinder , unwinder -> runtime_start_address +
302- unwinder -> debug_offsets .runtime_state .interpreters_head , & interp ) < 0 ) {
303- goto unavailable ;
304- }
305- while (interp && remaining -- > 0 ) {
306- if (read_ptr (unwinder , interp +
307- unwinder -> debug_offsets .interpreter_state .threads_head , & tstate ) < 0 ) {
308- goto unavailable ;
309- }
310- while (tstate && remaining -- > 0 ) {
311- char ts [SIZEOF_THREAD_STATE ];
312- if (_Py_RemoteDebug_ReadRemoteMemory (& unwinder -> handle , tstate ,
313- unwinder -> debug_offsets .thread_state .size , ts ) < 0 ) {
314- goto unavailable ;
315- }
316- if (GET_MEMBER (long , ts , unwinder -> debug_offsets .thread_state .native_thread_id ) == tid &&
317- GET_MEMBER (_thread_status , ts , unwinder -> debug_offsets .thread_state .status ).bound_gilstate ) {
318- uintptr_t frame = GET_MEMBER (uintptr_t , ts , unwinder -> debug_offsets .thread_state .current_frame );
319- uintptr_t base = GET_MEMBER (uintptr_t , ts , unwinder -> debug_offsets .thread_state .base_frame );
320- while (frame && frame != base && remaining -- > 0 ) {
321- char data [SIZEOF_INTERP_FRAME ];
322- if (_Py_RemoteDebug_ReadRemoteMemory (& unwinder -> handle , frame ,
323- sizeof (data ), data ) < 0 ) {
324- goto unavailable ;
325- }
326- int valid = is_frame_valid (unwinder , (uintptr_t )data ,
327- GET_MEMBER_NO_TAG (uintptr_t , data , unwinder -> debug_offsets .interpreter_frame .executable ));
328- if (valid < 0 ) {
329- goto unavailable ;
330- }
331- if (valid == 1 ) {
332- return 1 ;
333- }
334- frame = GET_MEMBER (uintptr_t , data , unwinder -> debug_offsets .interpreter_frame .previous );
335- }
336- }
337- tstate = GET_MEMBER (uintptr_t , ts , unwinder -> debug_offsets .thread_state .next );
338- }
339- if (read_ptr (unwinder , interp +
340- unwinder -> debug_offsets .interpreter_state .next , & interp ) < 0 ) {
341- goto unavailable ;
342- }
343- }
344- return 0 ;
345-
346- unavailable :
347- // Keep the sample when remote state changes during the lookup.
348- PyErr_Clear ();
349- return 0 ;
350- }
351-
352296static int
353297read_thread_state_and_maybe_frame (
354298 RemoteUnwinderObject * unwinder ,
@@ -388,7 +332,7 @@ PyObject*
388332unwind_stack_for_thread (
389333 RemoteUnwinderObject * unwinder ,
390334 uintptr_t * current_tstate ,
391- uintptr_t gil_holder_tstate ,
335+ int * has_unbound ,
392336 uintptr_t gc_frame ,
393337 uintptr_t main_thread_tstate ,
394338 const RemoteReadPrefetch * prefetch
@@ -557,11 +501,7 @@ unwind_stack_for_thread(
557501
558502 if (cpu_status == THREAD_STATE_UNKNOWN ) {
559503 status_flags |= THREAD_STATUS_UNKNOWN ;
560- } else if (cpu_status == THREAD_STATE_RUNNING &&
561- (GET_MEMBER (_thread_status , ts , unwinder -> debug_offsets .thread_state .status ).bound_gilstate ||
562- !has_bound_stack (unwinder , tid ))) {
563- // An unbound state may still be doing native work after a callback.
564- // Exclude it only if another bound stack shares the same OS thread.
504+ } else if (cpu_status == THREAD_STATE_RUNNING ) {
565505 status_flags |= THREAD_STATUS_ON_CPU ;
566506 }
567507
@@ -671,6 +611,13 @@ unwind_stack_for_thread(
671611 goto error ;
672612 }
673613
614+ if ((unwinder -> mode == PROFILING_MODE_CPU || unwinder -> mode == PROFILING_MODE_ALL ) &&
615+ !GET_MEMBER (_thread_status , ts , unwinder -> debug_offsets .thread_state .status ).bound_gilstate &&
616+ PyList_GET_SIZE (frame_info ) != 0 ) {
617+ status_flags |= THREAD_STATUS_UNBOUND ;
618+ * has_unbound = 1 ;
619+ }
620+
674621 // Always use status_flags
675622 PyObject * py_status = PyLong_FromLong (status_flags );
676623 if (py_status == NULL ) {
0 commit comments