@@ -138,47 +138,18 @@ typedef struct {
138
138
/* Counter for autogenerated Task names */
139
139
uint64_t task_name_counter ;
140
140
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
142
142
of it. Third party tasks implementations which don't inherit from
143
143
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
145
145
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
+
178
149
*/
179
150
180
151
struct {
181
- TaskObj tail ;
152
+ TaskObj first ;
182
153
TaskObj * head ;
183
154
} asyncio_tasks ;
184
155
@@ -1925,7 +1896,7 @@ register_task(asyncio_state *state, TaskObj *task)
1925
1896
{
1926
1897
ASYNCIO_STATE_LOCK (state );
1927
1898
assert (Task_Check (state , task ));
1928
- assert (task != & state -> asyncio_tasks .tail );
1899
+ assert (task != & state -> asyncio_tasks .first );
1929
1900
if (task -> next != NULL ) {
1930
1901
// already registered
1931
1902
goto exit ;
@@ -1934,8 +1905,10 @@ register_task(asyncio_state *state, TaskObj *task)
1934
1905
assert (state -> asyncio_tasks .head != NULL );
1935
1906
1936
1907
task -> next = state -> asyncio_tasks .head ;
1908
+ task -> prev = state -> asyncio_tasks .head -> prev ;
1909
+ state -> asyncio_tasks .head -> prev -> next = task ;
1937
1910
state -> asyncio_tasks .head -> prev = task ;
1938
- state -> asyncio_tasks . head = task ;
1911
+
1939
1912
exit :
1940
1913
ASYNCIO_STATE_UNLOCK (state );
1941
1914
}
@@ -1951,20 +1924,15 @@ unregister_task(asyncio_state *state, TaskObj *task)
1951
1924
{
1952
1925
ASYNCIO_STATE_LOCK (state );
1953
1926
assert (Task_Check (state , task ));
1954
- assert (task != & state -> asyncio_tasks .tail );
1927
+ assert (task != & state -> asyncio_tasks .first );
1955
1928
if (task -> next == NULL ) {
1956
1929
// not registered
1957
1930
assert (task -> prev == NULL );
1958
1931
assert (state -> asyncio_tasks .head != task );
1959
1932
goto exit ;
1960
1933
}
1961
1934
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 ;
1968
1936
task -> next = NULL ;
1969
1937
task -> prev = NULL ;
1970
1938
assert (state -> asyncio_tasks .head != task );
@@ -3657,12 +3625,10 @@ _asyncio_all_tasks_impl(PyObject *module, PyObject *loop)
3657
3625
Py_DECREF (eager_iter );
3658
3626
int err = 0 ;
3659
3627
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 ;
3661
3630
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 )
3666
3632
{
3667
3633
if (add_one_task (state , tasks , (PyObject * )head , loop ) < 0 ) {
3668
3634
Py_DECREF (tasks );
@@ -3875,9 +3841,12 @@ static int
3875
3841
module_exec (PyObject * mod )
3876
3842
{
3877
3843
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 ;
3881
3850
3882
3851
#define CREATE_TYPE (m , tp , spec , base ) \
3883
3852
do { \
0 commit comments