Skip to content

Commit ddf8dde

Browse files
committed
add reusable helper function
1 parent 6430f21 commit ddf8dde

3 files changed

Lines changed: 65 additions & 34 deletions

File tree

‎Modules/_remote_debugging/_remote_debugging.h‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ typedef enum _WIN32_THREADSTATE {
150150
#define MAX_SET_TABLE_SIZE (1 << 20) /* 1 million entries max for set iteration */
151151
#define MAX_FRAME_CHAIN_DEPTH (1024 + 512) /* Iteration bound for frame chain walks */
152152
#define MAX_TASK_WAITER_WALK_TASKS (1 << 14) /* Total-task bound for waiter walks */
153+
#define MAX_INTERPRETERS 256 /* Iteration bound for interpreter list walks */
153154

154155
#ifndef MAX
155156
#define MAX(a, b) ((a) > (b) ? (a) : (b))
@@ -488,6 +489,12 @@ typedef int (*interpreter_processor_func)(
488489
void *context
489490
);
490491

492+
typedef int (*unwinder_interpreter_func)(
493+
RemoteUnwinderObject *unwinder,
494+
uintptr_t interpreter_addr,
495+
void *context
496+
);
497+
491498

492499
/* ============================================================================
493500
* STRUCTSEQ DESCRIPTORS (extern declarations)

‎Modules/_remote_debugging/frames.c‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,6 @@ int
456456
clear_last_profiled_frames(RemoteUnwinderObject *unwinder)
457457
{
458458
uintptr_t current_interp = unwinder->interpreter_addr;
459-
const size_t MAX_INTERPRETERS = 256;
460459
size_t interp_count = 0;
461460

462461
while (current_interp != 0 && interp_count < MAX_INTERPRETERS) {

‎Modules/_remote_debugging/module.c‎

Lines changed: 58 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -598,6 +598,32 @@ refresh_generation_caches_for_interpreter(
598598
return 0;
599599
}
600600

601+
static int
602+
iterate_unwinder_interpreters(
603+
RemoteUnwinderObject *self,
604+
unwinder_interpreter_func func,
605+
void *context)
606+
{
607+
uintptr_t interp = self->interpreter_addr;
608+
for (size_t count = 0; interp != 0 && count < MAX_INTERPRETERS; count++) {
609+
if (refresh_generation_caches_for_interpreter(self, interp) < 0) {
610+
return -1;
611+
}
612+
if (func(self, interp, context) < 0) {
613+
return -1;
614+
}
615+
if (_Py_RemoteDebug_PagedReadRemoteMemory(
616+
&self->handle,
617+
interp + (uintptr_t)self->debug_offsets.interpreter_state.next,
618+
sizeof(void*),
619+
&interp) < 0) {
620+
set_exception_cause(self, PyExc_RuntimeError, "Failed to read next interpreter address");
621+
return -1;
622+
}
623+
}
624+
return 0;
625+
}
626+
601627
static int
602628
read_interp_state_and_maybe_thread_frame(
603629
RemoteUnwinderObject *unwinder,
@@ -903,6 +929,35 @@ _remote_debugging_RemoteUnwinder_get_stack_trace_impl(RemoteUnwinderObject *self
903929
return result;
904930
}
905931

932+
static int
933+
process_interpreter_for_awaited_by(
934+
RemoteUnwinderObject *self,
935+
uintptr_t interpreter_addr,
936+
void *context)
937+
{
938+
PyObject *result = (PyObject *)context;
939+
940+
// Process all threads
941+
if (iterate_threads(self, interpreter_addr, process_thread_for_awaited_by, result) < 0) {
942+
return -1;
943+
}
944+
945+
uintptr_t head_addr = interpreter_addr
946+
+ (uintptr_t)self->async_debug_offsets.asyncio_interpreter_state.asyncio_tasks_head;
947+
948+
// On top of a per-thread task lists used by default by asyncio to avoid
949+
// contention, there is also a fallback per-interpreter list of tasks;
950+
// any tasks still pending when a thread is destroyed will be moved to the
951+
// per-interpreter task list. It's unlikely we'll find anything here, but
952+
// interesting for debugging.
953+
if (append_awaited_by(self, 0, head_addr, result))
954+
{
955+
set_exception_cause(self, PyExc_RuntimeError, "Failed to append interpreter awaited_by in get_all_awaited_by");
956+
return -1;
957+
}
958+
return 0;
959+
}
960+
906961
/*[clinic input]
907962
@permit_long_docstring_body
908963
@critical_section
@@ -966,39 +1021,9 @@ _remote_debugging_RemoteUnwinder_get_all_awaited_by_impl(RemoteUnwinderObject *s
9661021
}
9671022

9681023
// gh-158880: Tasks live in every interpreter, not only the one at the list head
969-
uintptr_t interp = self->interpreter_addr;
970-
while (interp != 0) {
971-
if (refresh_generation_caches_for_interpreter(self, interp) < 0) {
972-
goto result_err;
973-
}
974-
975-
// Process all threads
976-
if (iterate_threads(self, interp, process_thread_for_awaited_by, result) < 0) {
977-
goto result_err;
978-
}
979-
980-
uintptr_t head_addr = interp
981-
+ (uintptr_t)self->async_debug_offsets.asyncio_interpreter_state.asyncio_tasks_head;
982-
983-
// On top of a per-thread task lists used by default by asyncio to avoid
984-
// contention, there is also a fallback per-interpreter list of tasks;
985-
// any tasks still pending when a thread is destroyed will be moved to
986-
// the per-interpreter task list. It's unlikely we'll find anything
987-
// here, but interesting for debugging.
988-
if (append_awaited_by(self, 0, head_addr, result))
989-
{
990-
set_exception_cause(self, PyExc_RuntimeError, "Failed to append interpreter awaited_by in get_all_awaited_by");
991-
goto result_err;
992-
}
993-
994-
if (_Py_RemoteDebug_PagedReadRemoteMemory(
995-
&self->handle,
996-
interp + (uintptr_t)self->debug_offsets.interpreter_state.next,
997-
sizeof(void*),
998-
&interp) < 0) {
999-
set_exception_cause(self, PyExc_RuntimeError, "Failed to read next interpreter address");
1000-
goto result_err;
1001-
}
1024+
if (iterate_unwinder_interpreters(self, process_interpreter_for_awaited_by,
1025+
result) < 0) {
1026+
goto result_err;
10021027
}
10031028

10041029
_Py_RemoteDebug_ClearCache(&self->handle);

0 commit comments

Comments
 (0)