@@ -116,13 +116,11 @@ ensure_async_debug_offsets(RemoteUnwinderObject *unwinder)
116116 * SET ITERATION FUNCTIONS
117117 * ============================================================================ */
118118
119- int
119+ static int
120120iterate_set_entries (
121121 RemoteUnwinderObject * unwinder ,
122122 uintptr_t set_addr ,
123- set_entry_processor_func processor ,
124- void * context ,
125- size_t depth
123+ PyObject * awaited_by
126124) {
127125 char set_object [SIZEOF_SET_OBJ ];
128126 if (_Py_RemoteDebug_PagedReadRemoteMemory (& unwinder -> handle , set_addr ,
@@ -154,19 +152,10 @@ iterate_set_entries(
154152 }
155153
156154 if ((void * )key_addr != NULL ) {
157- Py_ssize_t ref_cnt ;
158- if (read_Py_ssize_t (unwinder , table_ptr , & ref_cnt ) < 0 ) {
159- set_exception_cause (unwinder , PyExc_RuntimeError , "Failed to read set entry ref count" );
155+ if (parse_task (unwinder , key_addr , awaited_by ) < 0 ) {
160156 return -1 ;
161157 }
162-
163- if (ref_cnt ) {
164- // Process this valid set entry
165- if (processor (unwinder , key_addr , context , depth ) < 0 ) {
166- return -1 ;
167- }
168- els ++ ;
169- }
158+ els ++ ;
170159 }
171160 table_ptr += sizeof (void * ) * 2 ;
172161 i ++ ;
@@ -526,44 +515,11 @@ parse_task(
526515 * TASK AWAITED_BY PROCESSING
527516 * ============================================================================ */
528517
529- // Forward declaration for mutual recursion
530- static int process_waiter_task (
531- RemoteUnwinderObject * unwinder ,
532- uintptr_t key_addr ,
533- void * context ,
534- size_t depth
535- );
536-
537- // Processor function for parsing tasks in sets
538- static int
539- process_task_parser (
540- RemoteUnwinderObject * unwinder ,
541- uintptr_t key_addr ,
542- void * context ,
543- size_t depth
544- ) {
545- (void )depth ;
546- PyObject * awaited_by = (PyObject * )context ;
547- return parse_task (unwinder , key_addr , awaited_by );
548- }
549-
550518static int
551519parse_task_awaited_by (
552520 RemoteUnwinderObject * unwinder ,
553521 uintptr_t task_address ,
554522 PyObject * awaited_by
555- ) {
556- return process_task_awaited_by (
557- unwinder , task_address , process_task_parser , awaited_by , 0 );
558- }
559-
560- int
561- process_task_awaited_by (
562- RemoteUnwinderObject * unwinder ,
563- uintptr_t task_address ,
564- set_entry_processor_func processor ,
565- void * context ,
566- size_t depth
567523) {
568524 // Read the entire TaskObj at once
569525 char task_obj [SIZEOF_TASK_OBJ ];
@@ -582,11 +538,10 @@ process_task_awaited_by(
582538 char awaited_by_is_a_set = GET_MEMBER (char , task_obj , unwinder -> async_debug_offsets .asyncio_task_object .task_awaited_by_is_set );
583539
584540 if (awaited_by_is_a_set ) {
585- return iterate_set_entries (
586- unwinder , task_ab_addr , processor , context , depth );
541+ return iterate_set_entries (unwinder , task_ab_addr , awaited_by );
587542 } else {
588543 // Single task waiting
589- return processor (unwinder , task_ab_addr , context , depth );
544+ return parse_task (unwinder , task_ab_addr , awaited_by );
590545 }
591546}
592547
@@ -681,40 +636,39 @@ process_single_task_node(
681636 return -1 ;
682637}
683638
684- int
685- process_task_and_waiters (
639+ static int
640+ process_task_waiters (
686641 RemoteUnwinderObject * unwinder ,
687- uintptr_t task_addr ,
688- PyObject * result ,
689- size_t depth
642+ PyObject * result
690643) {
691- if (depth >= MAX_TASK_WAITER_CHAIN_DEPTH ) {
692- PyErr_SetString (PyExc_RuntimeError ,
693- "Too many task waiters (possible infinite loop)" );
694- set_exception_cause (unwinder , PyExc_RuntimeError ,
695- "Task waiter chain depth limit exceeded" );
696- return -1 ;
697- }
698-
699- // First, add this task to the result
700- if (process_single_task_node (unwinder , task_addr , NULL , result ) < 0 ) {
701- return -1 ;
644+ for (Py_ssize_t i = 0 ; i < PyList_GET_SIZE (result ); i ++ ) {
645+ PyObject * task_info = PyList_GET_ITEM (result , i );
646+ PyObject * waiters = PyStructSequence_GET_ITEM (task_info , 3 );
647+ for (Py_ssize_t j = 0 ; j < PyList_GET_SIZE (waiters ); j ++ ) {
648+ if (PyList_GET_SIZE (result ) >= MAX_TASK_WAITER_WALK_TASKS ) {
649+ PyErr_SetString (PyExc_RuntimeError ,
650+ "Too many task waiters (possible infinite loop)" );
651+ set_exception_cause (unwinder , PyExc_RuntimeError ,
652+ "Task waiter walk size limit exceeded" );
653+ return -1 ;
654+ }
655+ PyObject * waiter = PyList_GET_ITEM (waiters , j );
656+ PyObject * task_id = PyStructSequence_GET_ITEM (waiter , 1 );
657+ void * task_ptr = PyLong_AsVoidPtr (task_id );
658+ if (task_ptr == NULL && PyErr_Occurred ()) {
659+ set_exception_cause (unwinder , PyExc_RuntimeError ,
660+ "Failed to parse waiter task ID" );
661+ return -1 ;
662+ }
663+ if (process_single_task_node (
664+ unwinder , (uintptr_t )task_ptr , NULL , result ) < 0 )
665+ {
666+ return -1 ;
667+ }
668+ }
702669 }
703670
704- // Now find all tasks that are waiting for this task and process them
705- return process_task_awaited_by (
706- unwinder , task_addr , process_waiter_task , result , depth + 1 );
707- }
708-
709- // Processor function for task waiters
710- static int
711- process_waiter_task (
712- RemoteUnwinderObject * unwinder ,
713- uintptr_t key_addr ,
714- void * context ,
715- size_t depth
716- ) {
717- return process_task_and_waiters (unwinder , key_addr , (PyObject * )context , depth );
671+ return 0 ;
718672}
719673
720674/* ============================================================================
@@ -1017,9 +971,7 @@ process_running_task_chain(
1017971 }
1018972
1019973 // Now find all tasks that are waiting for this task and process them
1020- if (process_task_awaited_by (
1021- unwinder , running_task_addr , process_waiter_task , result , 1 ) < 0 )
1022- {
974+ if (process_task_waiters (unwinder , result ) < 0 ) {
1023975 return -1 ;
1024976 }
1025977
0 commit comments