66#include "pycore_critical_section.h" // Py_BEGIN_CRITICAL_SECTION_MUT()
77#include "pycore_dict.h" // _PyDict_GetItem_KnownHash()
88#include "pycore_freelist.h" // _Py_FREELIST_POP()
9+ #include "pycore_llist.h" // struct llist_node
910#include "pycore_modsupport.h" // _PyArg_CheckPositional()
1011#include "pycore_moduleobject.h" // _PyModule_GetState()
11- #include "pycore_object.h" // _Py_SetImmortalUntracked()
1212#include "pycore_pyerrors.h" // _PyErr_ClearExcState()
1313#include "pycore_pylifecycle.h" // _Py_IsInterpreterFinalizing()
1414#include "pycore_pystate.h" // _PyThreadState_GET()
@@ -60,8 +60,7 @@ typedef struct TaskObj {
6060 PyObject * task_coro ;
6161 PyObject * task_name ;
6262 PyObject * task_context ;
63- struct TaskObj * next ;
64- struct TaskObj * prev ;
63+ struct llist_node task_node ;
6564} TaskObj ;
6665
6766typedef struct {
@@ -136,21 +135,11 @@ typedef struct {
136135 /* Counter for autogenerated Task names */
137136 uint64_t task_name_counter ;
138137
139- /* Circular linked-list of all tasks which are instances of asyncio.Task or subclasses
140- of it. Third party tasks implementations which don't inherit from
141- asyncio.Task are tracked separately using the 'non_asyncio_tasks' WeakSet.
142- `first` is used as a sentinel to mark the end of the linked-list. It avoids one
143- branch in checking for empty list when adding a new task, the list is
144- initialized with `head`, `head->next` and `head->prev` pointing to `first`
145- to mark an empty list.
146-
138+ /* Head of circular linked-list of all tasks which are instances of `asyncio.Task`
139+ or subclasses of it. Third party tasks implementations which don't inherit from
140+ `asyncio.Task` are tracked separately using the `non_asyncio_tasks` WeakSet.
147141 */
148-
149- struct {
150- TaskObj first ;
151- TaskObj * head ;
152- } asyncio_tasks ;
153-
142+ struct llist_node asyncio_tasks_head ;
154143} asyncio_state ;
155144
156145static inline asyncio_state *
@@ -1896,19 +1885,12 @@ register_task(asyncio_state *state, TaskObj *task)
18961885{
18971886 ASYNCIO_STATE_LOCK (state );
18981887 assert (Task_Check (state , task ));
1899- assert (task != & state -> asyncio_tasks .first );
1900- if (task -> next != NULL ) {
1888+ if (task -> task_node .next != NULL ) {
19011889 // already registered
1890+ assert (task -> task_node .prev != NULL );
19021891 goto exit ;
19031892 }
1904- assert (task -> prev == NULL );
1905- assert (state -> asyncio_tasks .head != NULL );
1906-
1907- task -> next = state -> asyncio_tasks .head ;
1908- task -> prev = state -> asyncio_tasks .head -> prev ;
1909- state -> asyncio_tasks .head -> prev -> next = task ;
1910- state -> asyncio_tasks .head -> prev = task ;
1911-
1893+ llist_insert_tail (& state -> asyncio_tasks_head , & task -> task_node );
19121894exit :
19131895 ASYNCIO_STATE_UNLOCK (state );
19141896}
@@ -1924,18 +1906,12 @@ unregister_task(asyncio_state *state, TaskObj *task)
19241906{
19251907 ASYNCIO_STATE_LOCK (state );
19261908 assert (Task_Check (state , task ));
1927- assert (task != & state -> asyncio_tasks .first );
1928- if (task -> next == NULL ) {
1909+ if (task -> task_node .next == NULL ) {
19291910 // not registered
1930- assert (task -> prev == NULL );
1931- assert (state -> asyncio_tasks .head != task );
1911+ assert (task -> task_node .prev == NULL );
19321912 goto exit ;
19331913 }
1934- task -> next -> prev = task -> prev ;
1935- task -> prev -> next = task -> next ;
1936- task -> next = NULL ;
1937- task -> prev = NULL ;
1938- assert (state -> asyncio_tasks .head != task );
1914+ llist_remove (& task -> task_node );
19391915exit :
19401916 ASYNCIO_STATE_UNLOCK (state );
19411917}
@@ -3625,20 +3601,18 @@ _asyncio_all_tasks_impl(PyObject *module, PyObject *loop)
36253601 Py_DECREF (eager_iter );
36263602 int err = 0 ;
36273603 ASYNCIO_STATE_LOCK (state );
3628- TaskObj * first = & state -> asyncio_tasks . first ;
3629- TaskObj * head = state -> asyncio_tasks . head -> next ;
3630- Py_INCREF ( head );
3631- while ( head != first )
3632- {
3633- if ( add_one_task ( state , tasks , ( PyObject * ) head , loop ) < 0 ) {
3604+ struct llist_node * node ;
3605+ llist_for_each_safe ( node , & state -> asyncio_tasks_head ) {
3606+ TaskObj * task = llist_data ( node , TaskObj , task_node );
3607+ Py_INCREF ( task );
3608+ if ( add_one_task ( state , tasks , ( PyObject * ) task , loop ) < 0 ) {
3609+ Py_DECREF ( task );
36343610 Py_DECREF (tasks );
36353611 Py_DECREF (loop );
3636- Py_DECREF (head );
36373612 err = 1 ;
36383613 break ;
36393614 }
3640- Py_INCREF (head -> next );
3641- Py_SETREF (head , head -> next );
3615+ Py_DECREF (task );
36423616 }
36433617 ASYNCIO_STATE_UNLOCK (state );
36443618 if (err ) {
@@ -3847,11 +3821,7 @@ module_exec(PyObject *mod)
38473821{
38483822 asyncio_state * state = get_asyncio_state (mod );
38493823
3850- Py_SET_TYPE (& state -> asyncio_tasks .first , state -> TaskType );
3851- _Py_SetImmortalUntracked ((PyObject * )& state -> asyncio_tasks .first );
3852- state -> asyncio_tasks .head = & state -> asyncio_tasks .first ;
3853- state -> asyncio_tasks .head -> next = & state -> asyncio_tasks .first ;
3854- state -> asyncio_tasks .head -> prev = & state -> asyncio_tasks .first ;
3824+ llist_init (& state -> asyncio_tasks_head );
38553825
38563826#define CREATE_TYPE (m , tp , spec , base ) \
38573827 do { \
0 commit comments