@@ -136,47 +136,18 @@ typedef struct {
136136 /* Counter for autogenerated Task names */
137137 uint64_t task_name_counter ;
138138
139- /* Linked -list of all tasks which are instances of asyncio.Task or subclasses
139+ /* Circular linked -list of all tasks which are instances of asyncio.Task or subclasses
140140 of it. Third party tasks implementations which don't inherit from
141141 asyncio.Task are tracked separately using the 'non_asyncio_tasks' WeakSet.
142- `tail ` is used as a sentinel to mark the end of the linked-list. It avoids one
142+ `first ` is used as a sentinel to mark the end of the linked-list. It avoids one
143143 branch in checking for empty list when adding a new task, the list is
144- initialized with `head` pointing to `tail` to mark an empty list.
145-
146- Invariants:
147- * When the list is empty:
148- - asyncio_tasks.head == &asyncio_tasks.tail
149- - asyncio_tasks.head->prev == NULL
150- - asyncio_tasks.head->next == NULL
151-
152- * After adding the first task 'task1':
153- - asyncio_tasks.head == task1
154- - task1->next == &asyncio_tasks.tail
155- - task1->prev == NULL
156- - asyncio_tasks.tail.prev == task1
157-
158- * After adding a second task 'task2':
159- - asyncio_tasks.head == task2
160- - task2->next == task1
161- - task2->prev == NULL
162- - task1->prev == task2
163- - asyncio_tasks.tail.prev == task1
164-
165- * After removing task 'task1':
166- - asyncio_tasks.head == task2
167- - task2->next == &asyncio_tasks.tail
168- - task2->prev == NULL
169- - asyncio_tasks.tail.prev == task2
170-
171- * After removing task 'task2', the list is empty:
172- - asyncio_tasks.head == &asyncio_tasks.tail
173- - asyncio_tasks.head->prev == NULL
174- - asyncio_tasks.tail.prev == NULL
175- - asyncio_tasks.tail.next == NULL
144+ initialized with `head`, `head->next` and `head->prev` pointing to `first`
145+ to mark an empty list.
146+
176147 */
177148
178149 struct {
179- TaskObj tail ;
150+ TaskObj first ;
180151 TaskObj * head ;
181152 } asyncio_tasks ;
182153
@@ -1923,7 +1894,7 @@ register_task(asyncio_state *state, TaskObj *task)
19231894{
19241895 ASYNCIO_STATE_LOCK (state );
19251896 assert (Task_Check (state , task ));
1926- assert (task != & state -> asyncio_tasks .tail );
1897+ assert (task != & state -> asyncio_tasks .first );
19271898 if (task -> next != NULL ) {
19281899 // already registered
19291900 goto exit ;
@@ -1932,8 +1903,10 @@ register_task(asyncio_state *state, TaskObj *task)
19321903 assert (state -> asyncio_tasks .head != NULL );
19331904
19341905 task -> next = state -> asyncio_tasks .head ;
1906+ task -> prev = state -> asyncio_tasks .head -> prev ;
1907+ state -> asyncio_tasks .head -> prev -> next = task ;
19351908 state -> asyncio_tasks .head -> prev = task ;
1936- state -> asyncio_tasks . head = task ;
1909+
19371910exit :
19381911 ASYNCIO_STATE_UNLOCK (state );
19391912}
@@ -1949,20 +1922,15 @@ unregister_task(asyncio_state *state, TaskObj *task)
19491922{
19501923 ASYNCIO_STATE_LOCK (state );
19511924 assert (Task_Check (state , task ));
1952- assert (task != & state -> asyncio_tasks .tail );
1925+ assert (task != & state -> asyncio_tasks .first );
19531926 if (task -> next == NULL ) {
19541927 // not registered
19551928 assert (task -> prev == NULL );
19561929 assert (state -> asyncio_tasks .head != task );
19571930 goto exit ;
19581931 }
19591932 task -> next -> prev = task -> prev ;
1960- if (task -> prev == NULL ) {
1961- assert (state -> asyncio_tasks .head == task );
1962- state -> asyncio_tasks .head = task -> next ;
1963- } else {
1964- task -> prev -> next = task -> next ;
1965- }
1933+ task -> prev -> next = task -> next ;
19661934 task -> next = NULL ;
19671935 task -> prev = NULL ;
19681936 assert (state -> asyncio_tasks .head != task );
@@ -3655,12 +3623,10 @@ _asyncio_all_tasks_impl(PyObject *module, PyObject *loop)
36553623 Py_DECREF (eager_iter );
36563624 int err = 0 ;
36573625 ASYNCIO_STATE_LOCK (state );
3658- TaskObj * head = state -> asyncio_tasks .head ;
3626+ TaskObj * first = & state -> asyncio_tasks .first ;
3627+ TaskObj * head = state -> asyncio_tasks .head -> next ;
36593628 Py_INCREF (head );
3660- assert (head != NULL );
3661- assert (head -> prev == NULL );
3662- TaskObj * tail = & state -> asyncio_tasks .tail ;
3663- while (head != tail )
3629+ while (head != first )
36643630 {
36653631 if (add_one_task (state , tasks , (PyObject * )head , loop ) < 0 ) {
36663632 Py_DECREF (tasks );
@@ -3873,9 +3839,12 @@ static int
38733839module_exec (PyObject * mod )
38743840{
38753841 asyncio_state * state = get_asyncio_state (mod );
3876- Py_SET_TYPE (& state -> asyncio_tasks .tail , state -> TaskType );
3877- _Py_SetImmortalUntracked ((PyObject * )& state -> asyncio_tasks .tail );
3878- state -> asyncio_tasks .head = & state -> asyncio_tasks .tail ;
3842+
3843+ Py_SET_TYPE (& state -> asyncio_tasks .first , state -> TaskType );
3844+ _Py_SetImmortalUntracked ((PyObject * )& state -> asyncio_tasks .first );
3845+ state -> asyncio_tasks .head = & state -> asyncio_tasks .first ;
3846+ state -> asyncio_tasks .head -> next = & state -> asyncio_tasks .first ;
3847+ state -> asyncio_tasks .head -> prev = & state -> asyncio_tasks .first ;
38793848
38803849#define CREATE_TYPE (m , tp , spec , base ) \
38813850 do { \
0 commit comments