mirror of
https://github.com/python/cpython.git
synced 2025-08-04 00:48:58 +00:00
[3.14] gh-135371: Fix asyncio introspection output to include internal coroutine chains (GH-135436) (#135509)
gh-135371: Fix asyncio introspection output to include internal coroutine chains (GH-135436)
(cherry picked from commit 028309fb47
)
Co-authored-by: Pablo Galindo Salgado <Pablogsal@gmail.com>
This commit is contained in:
parent
6ae54553d4
commit
f8f99b1cfc
6 changed files with 1838 additions and 663 deletions
|
@ -97,24 +97,82 @@ struct _Py_AsyncioModuleDebugOffsets {
|
|||
} asyncio_thread_state;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
proc_handle_t handle;
|
||||
uintptr_t runtime_start_address;
|
||||
struct _Py_DebugOffsets debug_offsets;
|
||||
int async_debug_offsets_available;
|
||||
struct _Py_AsyncioModuleDebugOffsets async_debug_offsets;
|
||||
uintptr_t interpreter_addr;
|
||||
uintptr_t tstate_addr;
|
||||
uint64_t code_object_generation;
|
||||
_Py_hashtable_t *code_object_cache;
|
||||
int debug;
|
||||
#ifdef Py_GIL_DISABLED
|
||||
// TLBC cache invalidation tracking
|
||||
uint32_t tlbc_generation; // Track TLBC index pool changes
|
||||
_Py_hashtable_t *tlbc_cache; // Cache of TLBC arrays by code object address
|
||||
#endif
|
||||
} RemoteUnwinderObject;
|
||||
/* ============================================================================
|
||||
* STRUCTSEQ TYPE DEFINITIONS
|
||||
* ============================================================================ */
|
||||
|
||||
// TaskInfo structseq type - replaces 4-tuple (task_id, task_name, coroutine_stack, awaited_by)
|
||||
static PyStructSequence_Field TaskInfo_fields[] = {
|
||||
{"task_id", "Task ID (memory address)"},
|
||||
{"task_name", "Task name"},
|
||||
{"coroutine_stack", "Coroutine call stack"},
|
||||
{"awaited_by", "Tasks awaiting this task"},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
static PyStructSequence_Desc TaskInfo_desc = {
|
||||
"_remote_debugging.TaskInfo",
|
||||
"Information about an asyncio task",
|
||||
TaskInfo_fields,
|
||||
4
|
||||
};
|
||||
|
||||
// FrameInfo structseq type - replaces 3-tuple (filename, lineno, funcname)
|
||||
static PyStructSequence_Field FrameInfo_fields[] = {
|
||||
{"filename", "Source code filename"},
|
||||
{"lineno", "Line number"},
|
||||
{"funcname", "Function name"},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
static PyStructSequence_Desc FrameInfo_desc = {
|
||||
"_remote_debugging.FrameInfo",
|
||||
"Information about a frame",
|
||||
FrameInfo_fields,
|
||||
3
|
||||
};
|
||||
|
||||
// CoroInfo structseq type - replaces 2-tuple (call_stack, task_name)
|
||||
static PyStructSequence_Field CoroInfo_fields[] = {
|
||||
{"call_stack", "Coroutine call stack"},
|
||||
{"task_name", "Task name"},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
static PyStructSequence_Desc CoroInfo_desc = {
|
||||
"_remote_debugging.CoroInfo",
|
||||
"Information about a coroutine",
|
||||
CoroInfo_fields,
|
||||
2
|
||||
};
|
||||
|
||||
// ThreadInfo structseq type - replaces 2-tuple (thread_id, frame_info)
|
||||
static PyStructSequence_Field ThreadInfo_fields[] = {
|
||||
{"thread_id", "Thread ID"},
|
||||
{"frame_info", "Frame information"},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
static PyStructSequence_Desc ThreadInfo_desc = {
|
||||
"_remote_debugging.ThreadInfo",
|
||||
"Information about a thread",
|
||||
ThreadInfo_fields,
|
||||
2
|
||||
};
|
||||
|
||||
// AwaitedInfo structseq type - replaces 2-tuple (tid, awaited_by_list)
|
||||
static PyStructSequence_Field AwaitedInfo_fields[] = {
|
||||
{"thread_id", "Thread ID"},
|
||||
{"awaited_by", "List of tasks awaited by this thread"},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
static PyStructSequence_Desc AwaitedInfo_desc = {
|
||||
"_remote_debugging.AwaitedInfo",
|
||||
"Information about what a thread is awaiting",
|
||||
AwaitedInfo_fields,
|
||||
2
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
PyObject *func_name;
|
||||
|
@ -127,8 +185,33 @@ typedef struct {
|
|||
typedef struct {
|
||||
/* Types */
|
||||
PyTypeObject *RemoteDebugging_Type;
|
||||
PyTypeObject *TaskInfo_Type;
|
||||
PyTypeObject *FrameInfo_Type;
|
||||
PyTypeObject *CoroInfo_Type;
|
||||
PyTypeObject *ThreadInfo_Type;
|
||||
PyTypeObject *AwaitedInfo_Type;
|
||||
} RemoteDebuggingState;
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
proc_handle_t handle;
|
||||
uintptr_t runtime_start_address;
|
||||
struct _Py_DebugOffsets debug_offsets;
|
||||
int async_debug_offsets_available;
|
||||
struct _Py_AsyncioModuleDebugOffsets async_debug_offsets;
|
||||
uintptr_t interpreter_addr;
|
||||
uintptr_t tstate_addr;
|
||||
uint64_t code_object_generation;
|
||||
_Py_hashtable_t *code_object_cache;
|
||||
int debug;
|
||||
RemoteDebuggingState *cached_state; // Cached module state
|
||||
#ifdef Py_GIL_DISABLED
|
||||
// TLBC cache invalidation tracking
|
||||
uint32_t tlbc_generation; // Track TLBC index pool changes
|
||||
_Py_hashtable_t *tlbc_cache; // Cache of TLBC arrays by code object address
|
||||
#endif
|
||||
} RemoteUnwinderObject;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int lineno;
|
||||
|
@ -218,6 +301,24 @@ RemoteDebugging_GetState(PyObject *module)
|
|||
return (RemoteDebuggingState *)state;
|
||||
}
|
||||
|
||||
static inline RemoteDebuggingState *
|
||||
RemoteDebugging_GetStateFromType(PyTypeObject *type)
|
||||
{
|
||||
PyObject *module = PyType_GetModule(type);
|
||||
assert(module != NULL);
|
||||
return RemoteDebugging_GetState(module);
|
||||
}
|
||||
|
||||
static inline RemoteDebuggingState *
|
||||
RemoteDebugging_GetStateFromObject(PyObject *obj)
|
||||
{
|
||||
RemoteUnwinderObject *unwinder = (RemoteUnwinderObject *)obj;
|
||||
if (unwinder->cached_state == NULL) {
|
||||
unwinder->cached_state = RemoteDebugging_GetStateFromType(Py_TYPE(obj));
|
||||
}
|
||||
return unwinder->cached_state;
|
||||
}
|
||||
|
||||
static inline int
|
||||
RemoteDebugging_InitState(RemoteDebuggingState *st)
|
||||
{
|
||||
|
@ -854,24 +955,14 @@ create_task_result(
|
|||
char task_obj[SIZEOF_TASK_OBJ];
|
||||
uintptr_t coro_addr;
|
||||
|
||||
result = PyList_New(0);
|
||||
if (result == NULL) {
|
||||
set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create task result list");
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Create call_stack first since it's the first tuple element
|
||||
call_stack = PyList_New(0);
|
||||
if (call_stack == NULL) {
|
||||
set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create call stack list");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (PyList_Append(result, call_stack)) {
|
||||
set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to append call stack to task result");
|
||||
goto error;
|
||||
}
|
||||
Py_CLEAR(call_stack);
|
||||
|
||||
// Create task name/address for second tuple element
|
||||
if (recurse_task) {
|
||||
tn = parse_task_name(unwinder, task_address);
|
||||
} else {
|
||||
|
@ -882,12 +973,6 @@ create_task_result(
|
|||
goto error;
|
||||
}
|
||||
|
||||
if (PyList_Append(result, tn)) {
|
||||
set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to append task name to result");
|
||||
goto error;
|
||||
}
|
||||
Py_CLEAR(tn);
|
||||
|
||||
// Parse coroutine chain
|
||||
if (_Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, task_address,
|
||||
unwinder->async_debug_offsets.asyncio_task_object.size,
|
||||
|
@ -900,31 +985,29 @@ create_task_result(
|
|||
coro_addr &= ~Py_TAG_BITS;
|
||||
|
||||
if ((void*)coro_addr != NULL) {
|
||||
call_stack = PyList_New(0);
|
||||
if (call_stack == NULL) {
|
||||
set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create coro call stack list");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (parse_coro_chain(unwinder, coro_addr, call_stack) < 0) {
|
||||
Py_DECREF(call_stack);
|
||||
set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse coroutine chain");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (PyList_Reverse(call_stack)) {
|
||||
Py_DECREF(call_stack);
|
||||
set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to reverse call stack");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (PyList_SetItem(result, 0, call_stack) < 0) {
|
||||
Py_DECREF(call_stack);
|
||||
set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to set call stack in result");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
// Create final CoroInfo result
|
||||
RemoteDebuggingState *state = RemoteDebugging_GetStateFromObject((PyObject*)unwinder);
|
||||
result = PyStructSequence_New(state->CoroInfo_Type);
|
||||
if (result == NULL) {
|
||||
set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create CoroInfo");
|
||||
goto error;
|
||||
}
|
||||
|
||||
// PyStructSequence_SetItem steals references, so we don't need to DECREF on success
|
||||
PyStructSequence_SetItem(result, 0, call_stack); // This steals the reference
|
||||
PyStructSequence_SetItem(result, 1, tn); // This steals the reference
|
||||
|
||||
return result;
|
||||
|
||||
error:
|
||||
|
@ -943,7 +1026,6 @@ parse_task(
|
|||
) {
|
||||
char is_task;
|
||||
PyObject* result = NULL;
|
||||
PyObject* awaited_by = NULL;
|
||||
int err;
|
||||
|
||||
err = read_char(
|
||||
|
@ -962,48 +1044,37 @@ parse_task(
|
|||
goto error;
|
||||
}
|
||||
} else {
|
||||
result = PyList_New(0);
|
||||
// Create an empty CoroInfo for non-task objects
|
||||
RemoteDebuggingState *state = RemoteDebugging_GetStateFromObject((PyObject*)unwinder);
|
||||
result = PyStructSequence_New(state->CoroInfo_Type);
|
||||
if (result == NULL) {
|
||||
set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create empty task result");
|
||||
set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create empty CoroInfo");
|
||||
goto error;
|
||||
}
|
||||
PyObject *empty_list = PyList_New(0);
|
||||
if (empty_list == NULL) {
|
||||
set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create empty list");
|
||||
goto error;
|
||||
}
|
||||
PyObject *task_name = PyLong_FromUnsignedLongLong(task_address);
|
||||
if (task_name == NULL) {
|
||||
Py_DECREF(empty_list);
|
||||
set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to create task name");
|
||||
goto error;
|
||||
}
|
||||
PyStructSequence_SetItem(result, 0, empty_list); // This steals the reference
|
||||
PyStructSequence_SetItem(result, 1, task_name); // This steals the reference
|
||||
}
|
||||
|
||||
if (PyList_Append(render_to, result)) {
|
||||
set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to append task result to render list");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (recurse_task) {
|
||||
awaited_by = PyList_New(0);
|
||||
if (awaited_by == NULL) {
|
||||
set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create awaited_by list");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (PyList_Append(result, awaited_by)) {
|
||||
set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to append awaited_by to result");
|
||||
goto error;
|
||||
}
|
||||
Py_DECREF(awaited_by);
|
||||
|
||||
/* awaited_by is borrowed from 'result' to simplify cleanup */
|
||||
if (parse_task_awaited_by(unwinder, task_address, awaited_by, 1) < 0) {
|
||||
// Clear the pointer so the cleanup doesn't try to decref it since
|
||||
// it's borrowed from 'result' and will be decrefed when result is
|
||||
// deleted.
|
||||
awaited_by = NULL;
|
||||
set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse task awaited_by relationships");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
Py_DECREF(result);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
Py_XDECREF(result);
|
||||
Py_XDECREF(awaited_by);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -1161,6 +1232,7 @@ process_single_task_node(
|
|||
PyObject *current_awaited_by = NULL;
|
||||
PyObject *task_id = NULL;
|
||||
PyObject *result_item = NULL;
|
||||
PyObject *coroutine_stack = NULL;
|
||||
|
||||
tn = parse_task_name(unwinder, task_addr);
|
||||
if (tn == NULL) {
|
||||
|
@ -1174,25 +1246,40 @@ process_single_task_node(
|
|||
goto error;
|
||||
}
|
||||
|
||||
// Extract the coroutine stack for this task
|
||||
coroutine_stack = PyList_New(0);
|
||||
if (coroutine_stack == NULL) {
|
||||
set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create coroutine stack list in single task node");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (parse_task(unwinder, task_addr, coroutine_stack, 0) < 0) {
|
||||
set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse task coroutine stack in single task node");
|
||||
goto error;
|
||||
}
|
||||
|
||||
task_id = PyLong_FromUnsignedLongLong(task_addr);
|
||||
if (task_id == NULL) {
|
||||
set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to create task ID in single task node");
|
||||
goto error;
|
||||
}
|
||||
|
||||
result_item = PyTuple_New(3);
|
||||
RemoteDebuggingState *state = RemoteDebugging_GetStateFromObject((PyObject*)unwinder);
|
||||
result_item = PyStructSequence_New(state->TaskInfo_Type);
|
||||
if (result_item == NULL) {
|
||||
set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create result tuple in single task node");
|
||||
set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create TaskInfo in single task node");
|
||||
goto error;
|
||||
}
|
||||
|
||||
PyTuple_SET_ITEM(result_item, 0, task_id); // steals ref
|
||||
PyTuple_SET_ITEM(result_item, 1, tn); // steals ref
|
||||
PyTuple_SET_ITEM(result_item, 2, current_awaited_by); // steals ref
|
||||
PyStructSequence_SetItem(result_item, 0, task_id); // steals ref
|
||||
PyStructSequence_SetItem(result_item, 1, tn); // steals ref
|
||||
PyStructSequence_SetItem(result_item, 2, coroutine_stack); // steals ref
|
||||
PyStructSequence_SetItem(result_item, 3, current_awaited_by); // steals ref
|
||||
|
||||
// References transferred to tuple
|
||||
task_id = NULL;
|
||||
tn = NULL;
|
||||
coroutine_stack = NULL;
|
||||
current_awaited_by = NULL;
|
||||
|
||||
if (PyList_Append(result, result_item)) {
|
||||
|
@ -1203,9 +1290,11 @@ process_single_task_node(
|
|||
Py_DECREF(result_item);
|
||||
|
||||
// Get back current_awaited_by reference for parse_task_awaited_by
|
||||
current_awaited_by = PyTuple_GET_ITEM(result_item, 2);
|
||||
current_awaited_by = PyStructSequence_GetItem(result_item, 3);
|
||||
if (parse_task_awaited_by(unwinder, task_addr, current_awaited_by, 0) < 0) {
|
||||
set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse awaited_by in single task node");
|
||||
// No cleanup needed here since all references were transferred to result_item
|
||||
// and result_item was already added to result list and decreffed
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -1216,6 +1305,7 @@ error:
|
|||
Py_XDECREF(current_awaited_by);
|
||||
Py_XDECREF(task_id);
|
||||
Py_XDECREF(result_item);
|
||||
Py_XDECREF(coroutine_stack);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -1554,17 +1644,18 @@ done_tlbc:
|
|||
goto error;
|
||||
}
|
||||
|
||||
tuple = PyTuple_New(3);
|
||||
RemoteDebuggingState *state = RemoteDebugging_GetStateFromObject((PyObject*)unwinder);
|
||||
tuple = PyStructSequence_New(state->FrameInfo_Type);
|
||||
if (!tuple) {
|
||||
set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create result tuple for code object");
|
||||
set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create FrameInfo for code object");
|
||||
goto error;
|
||||
}
|
||||
|
||||
Py_INCREF(meta->func_name);
|
||||
Py_INCREF(meta->file_name);
|
||||
PyTuple_SET_ITEM(tuple, 0, meta->file_name);
|
||||
PyTuple_SET_ITEM(tuple, 1, lineno);
|
||||
PyTuple_SET_ITEM(tuple, 2, meta->func_name);
|
||||
PyStructSequence_SetItem(tuple, 0, meta->file_name);
|
||||
PyStructSequence_SetItem(tuple, 1, lineno);
|
||||
PyStructSequence_SetItem(tuple, 2, meta->func_name);
|
||||
|
||||
*result = tuple;
|
||||
return 0;
|
||||
|
@ -2212,23 +2303,24 @@ append_awaited_by(
|
|||
return -1;
|
||||
}
|
||||
|
||||
PyObject *result_item = PyTuple_New(2);
|
||||
if (result_item == NULL) {
|
||||
Py_DECREF(tid_py);
|
||||
set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create awaited_by result tuple");
|
||||
return -1;
|
||||
}
|
||||
|
||||
PyObject* awaited_by_for_thread = PyList_New(0);
|
||||
if (awaited_by_for_thread == NULL) {
|
||||
Py_DECREF(tid_py);
|
||||
Py_DECREF(result_item);
|
||||
set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create awaited_by thread list");
|
||||
return -1;
|
||||
}
|
||||
|
||||
PyTuple_SET_ITEM(result_item, 0, tid_py); // steals ref
|
||||
PyTuple_SET_ITEM(result_item, 1, awaited_by_for_thread); // steals ref
|
||||
RemoteDebuggingState *state = RemoteDebugging_GetStateFromObject((PyObject*)unwinder);
|
||||
PyObject *result_item = PyStructSequence_New(state->AwaitedInfo_Type);
|
||||
if (result_item == NULL) {
|
||||
Py_DECREF(tid_py);
|
||||
Py_DECREF(awaited_by_for_thread);
|
||||
set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create AwaitedInfo");
|
||||
return -1;
|
||||
}
|
||||
|
||||
PyStructSequence_SetItem(result_item, 0, tid_py); // steals ref
|
||||
PyStructSequence_SetItem(result_item, 1, awaited_by_for_thread); // steals ref
|
||||
if (PyList_Append(result, result_item)) {
|
||||
Py_DECREF(result_item);
|
||||
set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to append awaited_by result item");
|
||||
|
@ -2352,14 +2444,15 @@ unwind_stack_for_thread(
|
|||
goto error;
|
||||
}
|
||||
|
||||
result = PyTuple_New(2);
|
||||
RemoteDebuggingState *state = RemoteDebugging_GetStateFromObject((PyObject*)unwinder);
|
||||
result = PyStructSequence_New(state->ThreadInfo_Type);
|
||||
if (result == NULL) {
|
||||
set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create thread unwind result tuple");
|
||||
set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create ThreadInfo");
|
||||
goto error;
|
||||
}
|
||||
|
||||
PyTuple_SET_ITEM(result, 0, thread_id); // Steals reference
|
||||
PyTuple_SET_ITEM(result, 1, frame_info); // Steals reference
|
||||
PyStructSequence_SetItem(result, 0, thread_id); // Steals reference
|
||||
PyStructSequence_SetItem(result, 1, frame_info); // Steals reference
|
||||
|
||||
cleanup_stack_chunks(&chunks);
|
||||
return result;
|
||||
|
@ -2414,6 +2507,7 @@ _remote_debugging_RemoteUnwinder___init___impl(RemoteUnwinderObject *self,
|
|||
/*[clinic end generated code: output=3982f2a7eba49334 input=48a762566b828e91]*/
|
||||
{
|
||||
self->debug = debug;
|
||||
self->cached_state = NULL;
|
||||
if (_Py_RemoteDebug_InitProcHandle(&self->handle, pid) < 0) {
|
||||
set_exception_cause(self, PyExc_RuntimeError, "Failed to initialize process handle");
|
||||
return -1;
|
||||
|
@ -2860,6 +2954,47 @@ _remote_debugging_exec(PyObject *m)
|
|||
if (PyModule_AddType(m, st->RemoteDebugging_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Initialize structseq types
|
||||
st->TaskInfo_Type = PyStructSequence_NewType(&TaskInfo_desc);
|
||||
if (st->TaskInfo_Type == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (PyModule_AddType(m, st->TaskInfo_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
st->FrameInfo_Type = PyStructSequence_NewType(&FrameInfo_desc);
|
||||
if (st->FrameInfo_Type == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (PyModule_AddType(m, st->FrameInfo_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
st->CoroInfo_Type = PyStructSequence_NewType(&CoroInfo_desc);
|
||||
if (st->CoroInfo_Type == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (PyModule_AddType(m, st->CoroInfo_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
st->ThreadInfo_Type = PyStructSequence_NewType(&ThreadInfo_desc);
|
||||
if (st->ThreadInfo_Type == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (PyModule_AddType(m, st->ThreadInfo_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
st->AwaitedInfo_Type = PyStructSequence_NewType(&AwaitedInfo_desc);
|
||||
if (st->AwaitedInfo_Type == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (PyModule_AddType(m, st->AwaitedInfo_Type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
#ifdef Py_GIL_DISABLED
|
||||
PyUnstable_Module_SetGIL(m, Py_MOD_GIL_NOT_USED);
|
||||
#endif
|
||||
|
@ -2878,6 +3013,11 @@ remote_debugging_traverse(PyObject *mod, visitproc visit, void *arg)
|
|||
{
|
||||
RemoteDebuggingState *state = RemoteDebugging_GetState(mod);
|
||||
Py_VISIT(state->RemoteDebugging_Type);
|
||||
Py_VISIT(state->TaskInfo_Type);
|
||||
Py_VISIT(state->FrameInfo_Type);
|
||||
Py_VISIT(state->CoroInfo_Type);
|
||||
Py_VISIT(state->ThreadInfo_Type);
|
||||
Py_VISIT(state->AwaitedInfo_Type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2886,6 +3026,11 @@ remote_debugging_clear(PyObject *mod)
|
|||
{
|
||||
RemoteDebuggingState *state = RemoteDebugging_GetState(mod);
|
||||
Py_CLEAR(state->RemoteDebugging_Type);
|
||||
Py_CLEAR(state->TaskInfo_Type);
|
||||
Py_CLEAR(state->FrameInfo_Type);
|
||||
Py_CLEAR(state->CoroInfo_Type);
|
||||
Py_CLEAR(state->ThreadInfo_Type);
|
||||
Py_CLEAR(state->AwaitedInfo_Type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue