Skip to content

Commit 28735e7

Browse files
traverse linked lists of all threads
1 parent 1a39d41 commit 28735e7

File tree

2 files changed

+25
-19
lines changed

2 files changed

+25
-19
lines changed

Include/internal/pycore_pystate.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,8 +182,8 @@ extern void _PyEval_StartTheWorldAll(_PyRuntimeState *runtime);
182182
// Perform a stop-the-world pause for threads in the specified interpreter.
183183
//
184184
// NOTE: This is a no-op outside of Py_GIL_DISABLED builds.
185-
extern void _PyEval_StopTheWorld(PyInterpreterState *interp);
186-
extern void _PyEval_StartTheWorld(PyInterpreterState *interp);
185+
extern PyAPI_FUNC(void) _PyEval_StopTheWorld(PyInterpreterState *interp);
186+
extern PyAPI_FUNC(void) _PyEval_StartTheWorld(PyInterpreterState *interp);
187187

188188

189189
static inline void

Modules/_asynciomodule.c

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3748,26 +3748,32 @@ _asyncio_all_tasks_impl(PyObject *module, PyObject *loop)
37483748
}
37493749
int err = 0;
37503750
struct llist_node *node;
3751-
_PyThreadStateImpl *ts = (_PyThreadStateImpl *)_PyThreadState_GET();
3752-
struct llist_node *head = &ts->asyncio_tasks_head;
3753-
llist_for_each_safe(node, head) {
3754-
TaskObj *task = llist_data(node, TaskObj, task_node);
3755-
// The linked list holds borrowed references to task
3756-
// as such it is possible that the task is concurrently
3757-
// deallocated while added to this list.
3758-
// To protect against concurrent deallocations,
3759-
// we first try to incref the task which would fail
3760-
// if it is concurrently getting deallocated in another thread,
3761-
// otherwise it gets added to the list.
3762-
if (_Py_TryIncref((PyObject *)task)) {
3763-
if (_PyList_AppendTakeRef((PyListObject *)tasks, (PyObject *)task) < 0) {
3764-
Py_DECREF(tasks);
3765-
Py_DECREF(loop);
3766-
err = 1;
3767-
break;
3751+
PyInterpreterState *interp = PyInterpreterState_Get();
3752+
_PyEval_StopTheWorld(interp);
3753+
_PyThreadStateImpl *ts = (_PyThreadStateImpl *)PyInterpreterState_ThreadHead(interp);
3754+
while (ts) {
3755+
struct llist_node *head = &ts->asyncio_tasks_head;
3756+
llist_for_each_safe(node, head) {
3757+
TaskObj *task = llist_data(node, TaskObj, task_node);
3758+
// The linked list holds borrowed references to task
3759+
// as such it is possible that the task is concurrently
3760+
// deallocated while added to this list.
3761+
// To protect against concurrent deallocations,
3762+
// we first try to incref the task which would fail
3763+
// if it is concurrently getting deallocated in another thread,
3764+
// otherwise it gets added to the list.
3765+
if (_Py_TryIncref((PyObject *)task)) {
3766+
if (_PyList_AppendTakeRef((PyListObject *)tasks, (PyObject *)task) < 0) {
3767+
Py_DECREF(tasks);
3768+
Py_DECREF(loop);
3769+
err = 1;
3770+
break;
3771+
}
37683772
}
37693773
}
3774+
ts = (_PyThreadStateImpl *)ts->base.next;
37703775
}
3776+
_PyEval_StartTheWorld(interp);
37713777
if (err) {
37723778
return NULL;
37733779
}

0 commit comments

Comments
 (0)