@@ -4075,30 +4075,44 @@ _asyncio_all_tasks_impl(PyObject *module, PyObject *loop)
40754075 return NULL ;
40764076 }
40774077
4078- PyInterpreterState * interp = PyInterpreterState_Get ();
4079- // Stop the world and traverse the per-thread linked list
4080- // of asyncio tasks for every thread, as well as the
4081- // interpreter's linked list, and add them to `tasks`.
4082- // The interpreter linked list is used for any lingering tasks
4083- // whose thread state has been deallocated while the task was
4084- // still alive. This can happen if a task is referenced by
4085- // a different thread, in which case the task is moved to
4086- // the interpreter's linked list from the thread's linked
4087- // list before deallocation. See PyThreadState_Clear.
4088- //
4089- // The stop-the-world pause is required so that no thread
4090- // modifies its linked list while being iterated here
4091- // in parallel. This design allows for lock-free
4092- // register_task/unregister_task for loops running in parallel
4093- // in different threads (the general case).
4094- _PyEval_StopTheWorld (interp );
4095- int ret = add_tasks_interp (interp , (PyListObject * )tasks );
4096- _PyEval_StartTheWorld (interp );
4097- if (ret < 0 ) {
4098- // call any escaping calls after starting the world to avoid any deadlocks.
4099- Py_DECREF (tasks );
4100- Py_DECREF (loop );
4101- return NULL ;
4078+ _PyThreadStateImpl * ts = (_PyThreadStateImpl * )_PyThreadState_GET ();
4079+ if (ts -> asyncio_running_loop == loop ) {
4080+ // Fast path for the current running loop of current thread
4081+ // no locking or stop the world pause is required
4082+ struct llist_node * head = & ts -> asyncio_tasks_head ;
4083+ if (add_tasks_llist (head , (PyListObject * )tasks ) < 0 ) {
4084+ Py_DECREF (tasks );
4085+ Py_DECREF (loop );
4086+ return NULL ;
4087+ }
4088+ }
4089+ else {
4090+ // Slow path for loop running in different thread
4091+ PyInterpreterState * interp = ts -> base .interp ;
4092+ // Stop the world and traverse the per-thread linked list
4093+ // of asyncio tasks for every thread, as well as the
4094+ // interpreter's linked list, and add them to `tasks`.
4095+ // The interpreter linked list is used for any lingering tasks
4096+ // whose thread state has been deallocated while the task was
4097+ // still alive. This can happen if a task is referenced by
4098+ // a different thread, in which case the task is moved to
4099+ // the interpreter's linked list from the thread's linked
4100+ // list before deallocation. See PyThreadState_Clear.
4101+ //
4102+ // The stop-the-world pause is required so that no thread
4103+ // modifies its linked list while being iterated here
4104+ // in parallel. This design allows for lock-free
4105+ // register_task/unregister_task for loops running in parallel
4106+ // in different threads (the general case).
4107+ _PyEval_StopTheWorld (interp );
4108+ int ret = add_tasks_interp (interp , (PyListObject * )tasks );
4109+ _PyEval_StartTheWorld (interp );
4110+ if (ret < 0 ) {
4111+ // call any escaping calls after starting the world to avoid any deadlocks.
4112+ Py_DECREF (tasks );
4113+ Py_DECREF (loop );
4114+ return NULL ;
4115+ }
41024116 }
41034117
41044118 // All the tasks are now in the list, now filter the tasks which are done
0 commit comments