@@ -138,47 +138,18 @@ typedef struct {
138138 /* Counter for autogenerated Task names */
139139 uint64_t task_name_counter ;
140140
141- /* Linked -list of all tasks which are instances of asyncio.Task or subclasses
141+ /* Circular linked -list of all tasks which are instances of asyncio.Task or subclasses
142142 of it. Third party tasks implementations which don't inherit from
143143 asyncio.Task are tracked separately using the 'non_asyncio_tasks' WeakSet.
144- `tail ` is used as a sentinel to mark the end of the linked-list. It avoids one
144+ `first ` is used as a sentinel to mark the end of the linked-list. It avoids one
145145 branch in checking for empty list when adding a new task, the list is
146- initialized with `head` pointing to `tail` to mark an empty list.
147-
148- Invariants:
149- * When the list is empty:
150- - asyncio_tasks.head == &asyncio_tasks.tail
151- - asyncio_tasks.head->prev == NULL
152- - asyncio_tasks.head->next == NULL
153-
154- * After adding the first task 'task1':
155- - asyncio_tasks.head == task1
156- - task1->next == &asyncio_tasks.tail
157- - task1->prev == NULL
158- - asyncio_tasks.tail.prev == task1
159-
160- * After adding a second task 'task2':
161- - asyncio_tasks.head == task2
162- - task2->next == task1
163- - task2->prev == NULL
164- - task1->prev == task2
165- - asyncio_tasks.tail.prev == task1
166-
167- * After removing task 'task1':
168- - asyncio_tasks.head == task2
169- - task2->next == &asyncio_tasks.tail
170- - task2->prev == NULL
171- - asyncio_tasks.tail.prev == task2
172-
173- * After removing task 'task2', the list is empty:
174- - asyncio_tasks.head == &asyncio_tasks.tail
175- - asyncio_tasks.head->prev == NULL
176- - asyncio_tasks.tail.prev == NULL
177- - asyncio_tasks.tail.next == NULL
146+ initialized with `head`, `head->next` and `head->prev` pointing to `first`
147+ to mark an empty list.
148+
178149 */
179150
180151 struct {
181- TaskObj tail ;
152+ TaskObj first ;
182153 TaskObj * head ;
183154 } asyncio_tasks ;
184155
@@ -1925,7 +1896,7 @@ register_task(asyncio_state *state, TaskObj *task)
19251896{
19261897 ASYNCIO_STATE_LOCK (state );
19271898 assert (Task_Check (state , task ));
1928- assert (task != & state -> asyncio_tasks .tail );
1899+ assert (task != & state -> asyncio_tasks .first );
19291900 if (task -> next != NULL ) {
19301901 // already registered
19311902 goto exit ;
@@ -1934,8 +1905,10 @@ register_task(asyncio_state *state, TaskObj *task)
19341905 assert (state -> asyncio_tasks .head != NULL );
19351906
19361907 task -> next = state -> asyncio_tasks .head ;
1908+ task -> prev = state -> asyncio_tasks .head -> prev ;
1909+ state -> asyncio_tasks .head -> prev -> next = task ;
19371910 state -> asyncio_tasks .head -> prev = task ;
1938- state -> asyncio_tasks . head = task ;
1911+
19391912exit :
19401913 ASYNCIO_STATE_UNLOCK (state );
19411914}
@@ -1951,20 +1924,15 @@ unregister_task(asyncio_state *state, TaskObj *task)
19511924{
19521925 ASYNCIO_STATE_LOCK (state );
19531926 assert (Task_Check (state , task ));
1954- assert (task != & state -> asyncio_tasks .tail );
1927+ assert (task != & state -> asyncio_tasks .first );
19551928 if (task -> next == NULL ) {
19561929 // not registered
19571930 assert (task -> prev == NULL );
19581931 assert (state -> asyncio_tasks .head != task );
19591932 goto exit ;
19601933 }
19611934 task -> next -> prev = task -> prev ;
1962- if (task -> prev == NULL ) {
1963- assert (state -> asyncio_tasks .head == task );
1964- state -> asyncio_tasks .head = task -> next ;
1965- } else {
1966- task -> prev -> next = task -> next ;
1967- }
1935+ task -> prev -> next = task -> next ;
19681936 task -> next = NULL ;
19691937 task -> prev = NULL ;
19701938 assert (state -> asyncio_tasks .head != task );
@@ -3657,12 +3625,10 @@ _asyncio_all_tasks_impl(PyObject *module, PyObject *loop)
36573625 Py_DECREF (eager_iter );
36583626 int err = 0 ;
36593627 ASYNCIO_STATE_LOCK (state );
3660- TaskObj * head = state -> asyncio_tasks .head ;
3628+ TaskObj * first = & state -> asyncio_tasks .first ;
3629+ TaskObj * head = state -> asyncio_tasks .head -> next ;
36613630 Py_INCREF (head );
3662- assert (head != NULL );
3663- assert (head -> prev == NULL );
3664- TaskObj * tail = & state -> asyncio_tasks .tail ;
3665- while (head != tail )
3631+ while (head != first )
36663632 {
36673633 if (add_one_task (state , tasks , (PyObject * )head , loop ) < 0 ) {
36683634 Py_DECREF (tasks );
@@ -3875,9 +3841,12 @@ static int
38753841module_exec (PyObject * mod )
38763842{
38773843 asyncio_state * state = get_asyncio_state (mod );
3878- Py_SET_TYPE (& state -> asyncio_tasks .tail , state -> TaskType );
3879- _Py_SetImmortalUntracked ((PyObject * )& state -> asyncio_tasks .tail );
3880- state -> asyncio_tasks .head = & state -> asyncio_tasks .tail ;
3844+
3845+ Py_SET_TYPE (& state -> asyncio_tasks .first , state -> TaskType );
3846+ _Py_SetImmortalUntracked ((PyObject * )& state -> asyncio_tasks .first );
3847+ state -> asyncio_tasks .head = & state -> asyncio_tasks .first ;
3848+ state -> asyncio_tasks .head -> next = & state -> asyncio_tasks .first ;
3849+ state -> asyncio_tasks .head -> prev = & state -> asyncio_tasks .first ;
38813850
38823851#define CREATE_TYPE (m , tp , spec , base ) \
38833852 do { \
0 commit comments