From 9af62fcb27c382b8f0d90591f8d6e0519cac0f0f Mon Sep 17 00:00:00 2001 From: Kumar Aditya Date: Fri, 8 Nov 2024 12:01:31 +0000 Subject: [PATCH] use circular double linked list --- Modules/_asynciomodule.c | 73 ++++++++++++---------------------------- 1 file changed, 21 insertions(+), 52 deletions(-) diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c index 214c18e966c4c1..58b57ae7a983c2 100644 --- a/Modules/_asynciomodule.c +++ b/Modules/_asynciomodule.c @@ -138,47 +138,18 @@ typedef struct { /* Counter for autogenerated Task names */ uint64_t task_name_counter; - /* Linked-list of all tasks which are instances of asyncio.Task or subclasses + /* 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. - `tail` is used as a sentinel to mark the end of the linked-list. It avoids one + `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` pointing to `tail` to mark an empty list. - - Invariants: - * When the list is empty: - - asyncio_tasks.head == &asyncio_tasks.tail - - asyncio_tasks.head->prev == NULL - - asyncio_tasks.head->next == NULL - - * After adding the first task 'task1': - - asyncio_tasks.head == task1 - - task1->next == &asyncio_tasks.tail - - task1->prev == NULL - - asyncio_tasks.tail.prev == task1 - - * After adding a second task 'task2': - - asyncio_tasks.head == task2 - - task2->next == task1 - - task2->prev == NULL - - task1->prev == task2 - - asyncio_tasks.tail.prev == task1 - - * After removing task 'task1': - - asyncio_tasks.head == task2 - - task2->next == &asyncio_tasks.tail - - task2->prev == NULL - - asyncio_tasks.tail.prev == task2 - - * After removing task 'task2', the list is empty: - - asyncio_tasks.head == &asyncio_tasks.tail - - asyncio_tasks.head->prev == NULL - - asyncio_tasks.tail.prev == NULL - - asyncio_tasks.tail.next == NULL + initialized with `head`, `head->next` and `head->prev` pointing to `first` + to mark an empty list. + */ struct { - TaskObj tail; + TaskObj first; TaskObj *head; } asyncio_tasks; @@ -1925,7 +1896,7 @@ register_task(asyncio_state *state, TaskObj *task) { ASYNCIO_STATE_LOCK(state); assert(Task_Check(state, task)); - assert(task != &state->asyncio_tasks.tail); + assert(task != &state->asyncio_tasks.first); if (task->next != NULL) { // already registered goto exit; @@ -1934,8 +1905,10 @@ register_task(asyncio_state *state, TaskObj *task) 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; - state->asyncio_tasks.head = task; + exit: ASYNCIO_STATE_UNLOCK(state); } @@ -1951,7 +1924,7 @@ unregister_task(asyncio_state *state, TaskObj *task) { ASYNCIO_STATE_LOCK(state); assert(Task_Check(state, task)); - assert(task != &state->asyncio_tasks.tail); + assert(task != &state->asyncio_tasks.first); if (task->next == NULL) { // not registered assert(task->prev == NULL); @@ -1959,12 +1932,7 @@ unregister_task(asyncio_state *state, TaskObj *task) goto exit; } task->next->prev = task->prev; - if (task->prev == NULL) { - assert(state->asyncio_tasks.head == task); - state->asyncio_tasks.head = task->next; - } else { - task->prev->next = task->next; - } + task->prev->next = task->next; task->next = NULL; task->prev = NULL; assert(state->asyncio_tasks.head != task); @@ -3657,12 +3625,10 @@ _asyncio_all_tasks_impl(PyObject *module, PyObject *loop) Py_DECREF(eager_iter); int err = 0; ASYNCIO_STATE_LOCK(state); - TaskObj *head = state->asyncio_tasks.head; + TaskObj *first = &state->asyncio_tasks.first; + TaskObj *head = state->asyncio_tasks.head->next; Py_INCREF(head); - assert(head != NULL); - assert(head->prev == NULL); - TaskObj *tail = &state->asyncio_tasks.tail; - while (head != tail) + while (head != first) { if (add_one_task(state, tasks, (PyObject *)head, loop) < 0) { Py_DECREF(tasks); @@ -3875,9 +3841,12 @@ static int module_exec(PyObject *mod) { asyncio_state *state = get_asyncio_state(mod); - Py_SET_TYPE(&state->asyncio_tasks.tail, state->TaskType); - _Py_SetImmortalUntracked((PyObject *)&state->asyncio_tasks.tail); - state->asyncio_tasks.head = &state->asyncio_tasks.tail; + + 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; #define CREATE_TYPE(m, tp, spec, base) \ do { \