]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
GH-120974: make `_asyncio.all_tasks` thread safe (#122801)
authorKumar Aditya <kumaraditya@python.org>
Sun, 11 Aug 2024 15:19:31 +0000 (20:49 +0530)
committerGitHub <noreply@github.com>
Sun, 11 Aug 2024 15:19:31 +0000 (20:49 +0530)
Make `_asyncio.all_tasks` thread safe, also changes state lock to use critical section.

Modules/_asynciomodule.c

index c6eb43f044fdbd9fee1a9044b23dfa50fad302b1..0a769c46b87ac8b85b2999beb2e4cc54cbced8fb 100644 (file)
@@ -3,6 +3,7 @@
 #endif
 
 #include "Python.h"
+#include "pycore_critical_section.h"  // Py_BEGIN_CRITICAL_SECTION_MUT()
 #include "pycore_dict.h"          // _PyDict_GetItem_KnownHash()
 #include "pycore_freelist.h"      // _Py_FREELIST_POP()
 #include "pycore_modsupport.h"    // _PyArg_CheckPositional()
@@ -77,8 +78,8 @@ typedef struct {
 #define Task_Check(state, obj) PyObject_TypeCheck(obj, state->TaskType)
 
 #ifdef Py_GIL_DISABLED
-#   define ASYNCIO_STATE_LOCK(state) PyMutex_Lock(&state->mutex)
-#   define ASYNCIO_STATE_UNLOCK(state) PyMutex_Unlock(&state->mutex)
+#   define ASYNCIO_STATE_LOCK(state) Py_BEGIN_CRITICAL_SECTION_MUT(&state->mutex)
+#   define ASYNCIO_STATE_UNLOCK(state) Py_END_CRITICAL_SECTION()
 #else
 #   define ASYNCIO_STATE_LOCK(state) ((void)state)
 #   define ASYNCIO_STATE_UNLOCK(state) ((void)state)
@@ -1923,8 +1924,7 @@ register_task(asyncio_state *state, TaskObj *task)
     assert(task != &state->asyncio_tasks.tail);
     if (task->next != NULL) {
         // already registered
-        ASYNCIO_STATE_UNLOCK(state);
-        return;
+        goto exit;
     }
     assert(task->prev == NULL);
     assert(state->asyncio_tasks.head != NULL);
@@ -1932,6 +1932,7 @@ register_task(asyncio_state *state, TaskObj *task)
     task->next = state->asyncio_tasks.head;
     state->asyncio_tasks.head->prev = task;
     state->asyncio_tasks.head = task;
+exit:
     ASYNCIO_STATE_UNLOCK(state);
 }
 
@@ -1951,8 +1952,7 @@ unregister_task(asyncio_state *state, TaskObj *task)
         // not registered
         assert(task->prev == NULL);
         assert(state->asyncio_tasks.head != task);
-        ASYNCIO_STATE_UNLOCK(state);
-        return;
+        goto exit;
     }
     task->next->prev = task->prev;
     if (task->prev == NULL) {
@@ -1964,6 +1964,7 @@ unregister_task(asyncio_state *state, TaskObj *task)
     task->next = NULL;
     task->prev = NULL;
     assert(state->asyncio_tasks.head != task);
+exit:
     ASYNCIO_STATE_UNLOCK(state);
 }
 
@@ -3628,6 +3629,8 @@ _asyncio_all_tasks_impl(PyObject *module, PyObject *loop)
         Py_DECREF(item);
     }
     Py_DECREF(eager_iter);
+    int err = 0;
+    ASYNCIO_STATE_LOCK(state);
     TaskObj *head = state->asyncio_tasks.head;
     Py_INCREF(head);
     assert(head != NULL);
@@ -3639,11 +3642,16 @@ _asyncio_all_tasks_impl(PyObject *module, PyObject *loop)
             Py_DECREF(tasks);
             Py_DECREF(loop);
             Py_DECREF(head);
-            return NULL;
+            err = 1;
+            break;
         }
         Py_INCREF(head->next);
         Py_SETREF(head, head->next);
     }
+    ASYNCIO_STATE_UNLOCK(state);
+    if (err) {
+        return NULL;
+    }
     PyObject *scheduled_iter = PyObject_GetIter(state->non_asyncio_tasks);
     if (scheduled_iter == NULL) {
         Py_DECREF(tasks);