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