diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c index 27c163644573365..603b77a70b15d4d 100644 --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -6,9 +6,9 @@ #include "pycore_critical_section.h" // Py_BEGIN_CRITICAL_SECTION_MUT() #include "pycore_dict.h" // _PyDict_GetItem_KnownHash() #include "pycore_freelist.h" // _Py_FREELIST_POP() +#include "pycore_llist.h" // struct llist_node #include "pycore_modsupport.h" // _PyArg_CheckPositional() #include "pycore_moduleobject.h" // _PyModule_GetState() -#include "pycore_object.h" // _Py_SetImmortalUntracked() #include "pycore_pyerrors.h" // _PyErr_ClearExcState() #include "pycore_pylifecycle.h" // _Py_IsInterpreterFinalizing() #include "pycore_pystate.h" // _PyThreadState_GET() @@ -60,8 +60,7 @@ typedef struct TaskObj { PyObject *task_coro; PyObject *task_name; PyObject *task_context; - struct TaskObj *next; - struct TaskObj *prev; + struct llist_node task_node; } TaskObj; typedef struct { @@ -136,21 +135,11 @@ typedef struct { /* Counter for autogenerated Task names */ uint64_t task_name_counter; - /* Circular linked-list of all tasks which are instances of asyncio.Task or subclasses - of it. Third party tasks implementations which don't inherit from - asyncio.Task are tracked separately using the 'non_asyncio_tasks' WeakSet. - `first` is used as a sentinel to mark the end of the linked-list. It avoids one - branch in checking for empty list when adding a new task, the list is - initialized with `head`, `head->next` and `head->prev` pointing to `first` - to mark an empty list. - + /* Head of circular linked-list of all tasks which are instances of `asyncio.Task` + or subclasses of it. Third party tasks implementations which don't inherit from + `asyncio.Task` are tracked separately using the `non_asyncio_tasks` WeakSet. */ - - struct { - TaskObj first; - TaskObj *head; - } asyncio_tasks; - + struct llist_node asyncio_tasks_head; } asyncio_state; static inline asyncio_state * @@ -1896,19 +1885,12 @@ register_task(asyncio_state *state, TaskObj *task) { ASYNCIO_STATE_LOCK(state); assert(Task_Check(state, task)); - assert(task != &state->asyncio_tasks.first); - if (task->next != NULL) { + if (task->task_node.next != NULL) { // already registered + assert(task->task_node.prev != NULL); goto exit; } - assert(task->prev == NULL); - assert(state->asyncio_tasks.head != NULL); - - task->next = state->asyncio_tasks.head; - task->prev = state->asyncio_tasks.head->prev; - state->asyncio_tasks.head->prev->next = task; - state->asyncio_tasks.head->prev = task; - + llist_insert_tail(&state->asyncio_tasks_head, &task->task_node); exit: ASYNCIO_STATE_UNLOCK(state); } @@ -1924,18 +1906,12 @@ unregister_task(asyncio_state *state, TaskObj *task) { ASYNCIO_STATE_LOCK(state); assert(Task_Check(state, task)); - assert(task != &state->asyncio_tasks.first); - if (task->next == NULL) { + if (task->task_node.next == NULL) { // not registered - assert(task->prev == NULL); - assert(state->asyncio_tasks.head != task); + assert(task->task_node.prev == NULL); goto exit; } - task->next->prev = task->prev; - task->prev->next = task->next; - task->next = NULL; - task->prev = NULL; - assert(state->asyncio_tasks.head != task); + llist_remove(&task->task_node); exit: ASYNCIO_STATE_UNLOCK(state); } @@ -3625,20 +3601,18 @@ _asyncio_all_tasks_impl(PyObject *module, PyObject *loop) Py_DECREF(eager_iter); int err = 0; ASYNCIO_STATE_LOCK(state); - TaskObj *first = &state->asyncio_tasks.first; - TaskObj *head = state->asyncio_tasks.head->next; - Py_INCREF(head); - while (head != first) - { - if (add_one_task(state, tasks, (PyObject *)head, loop) < 0) { + struct llist_node *node; + llist_for_each_safe(node, &state->asyncio_tasks_head) { + TaskObj *task = llist_data(node, TaskObj, task_node); + Py_INCREF(task); + if (add_one_task(state, tasks, (PyObject *)task, loop) < 0) { + Py_DECREF(task); Py_DECREF(tasks); Py_DECREF(loop); - Py_DECREF(head); err = 1; break; } - Py_INCREF(head->next); - Py_SETREF(head, head->next); + Py_DECREF(task); } ASYNCIO_STATE_UNLOCK(state); if (err) { @@ -3847,11 +3821,7 @@ module_exec(PyObject *mod) { asyncio_state *state = get_asyncio_state(mod); - Py_SET_TYPE(&state->asyncio_tasks.first, state->TaskType); - _Py_SetImmortalUntracked((PyObject *)&state->asyncio_tasks.first); - state->asyncio_tasks.head = &state->asyncio_tasks.first; - state->asyncio_tasks.head->next = &state->asyncio_tasks.first; - state->asyncio_tasks.head->prev = &state->asyncio_tasks.first; + llist_init(&state->asyncio_tasks_head); #define CREATE_TYPE(m, tp, spec, base) \ do { \