]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.13] gh-121621: Move asyncio running loop to thread state (GH-121695) (GH-121864)
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Tue, 16 Jul 2024 17:57:37 +0000 (19:57 +0200)
committerGitHub <noreply@github.com>
Tue, 16 Jul 2024 17:57:37 +0000 (01:57 +0800)
gh-121621: Move asyncio running loop to thread state (GH-121695)
(cherry picked from commit 69c68de43aef03dd52fabd21f99cb3b0f9329201)

Co-authored-by: Ken Jin <kenjin@python.org>
Include/cpython/pystate.h
Include/internal/pycore_global_objects_fini_generated.h
Include/internal/pycore_global_strings.h
Include/internal/pycore_runtime_init_generated.h
Include/internal/pycore_unicodeobject_generated.h
Modules/_asynciomodule.c
Python/pystate.c

index bb2af78a376d7515bd3f76ad7bd19447eac25fdd..ce050424cccd493641bf0b8627d8847ad3904545 100644 (file)
@@ -68,6 +68,8 @@ struct _ts {
        pycore_ceval.h. */
     uintptr_t eval_breaker;
 
+    PyObject *asyncio_running_loop; // Strong reference
+
     struct {
         /* Has been initialized to a safe state.
 
index 16cb4793ad1d086d504a4855c8b05982b6cafd8a..006dd911b5a8effeb83fb8cd55667a814aa6be06 100644 (file)
@@ -586,7 +586,6 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__anext__));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__annotations__));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__args__));
-    _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__asyncio_running_event_loop__));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__await__));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__bases__));
     _PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(__bool__));
index 1e76853297150b3be4e66ed2c28fecdd7cc72985..a5436b6d68961208355020a358df5628b0823186 100644 (file)
@@ -75,7 +75,6 @@ struct _Py_global_strings {
         STRUCT_FOR_ID(__anext__)
         STRUCT_FOR_ID(__annotations__)
         STRUCT_FOR_ID(__args__)
-        STRUCT_FOR_ID(__asyncio_running_event_loop__)
         STRUCT_FOR_ID(__await__)
         STRUCT_FOR_ID(__bases__)
         STRUCT_FOR_ID(__bool__)
index f4d0ee4122ea2fe2d0643e4e9814026966c244a6..6e62ecd4b3a8158790d3da217a0427826b74cd1c 100644 (file)
@@ -584,7 +584,6 @@ extern "C" {
     INIT_ID(__anext__), \
     INIT_ID(__annotations__), \
     INIT_ID(__args__), \
-    INIT_ID(__asyncio_running_event_loop__), \
     INIT_ID(__await__), \
     INIT_ID(__bases__), \
     INIT_ID(__bool__), \
index e1bc9cf1c7bd6e307141d172318e4a4d7df6a1fd..5337390309548bcb9b79ae7c971335a92ce69f9b 100644 (file)
@@ -104,10 +104,6 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
     _PyUnicode_InternStatic(interp, &string);
     assert(_PyUnicode_CheckConsistency(string, 1));
     assert(PyUnicode_GET_LENGTH(string) != 1);
-    string = &_Py_ID(__asyncio_running_event_loop__);
-    _PyUnicode_InternStatic(interp, &string);
-    assert(_PyUnicode_CheckConsistency(string, 1));
-    assert(PyUnicode_GET_LENGTH(string) != 1);
     string = &_Py_ID(__await__);
     _PyUnicode_InternStatic(interp, &string);
     assert(_PyUnicode_CheckConsistency(string, 1));
index 92d0e6de0dfb93e7aa6b800f90a12d6fb6ee7b9c..ab72cc2fe556374a41031c4d228f81eaaa9343a4 100644 (file)
@@ -68,9 +68,6 @@ typedef struct {
     /* Imports from traceback. */
     PyObject *traceback_extract_stack;
 
-    PyObject *cached_running_loop; // Borrowed reference
-    volatile uint64_t cached_running_loop_tsid;
-
     /* Counter for autogenerated Task names */
     uint64_t task_name_counter;
 
@@ -262,101 +259,15 @@ get_future_loop(asyncio_state *state, PyObject *fut)
     return PyObject_GetAttr(fut, &_Py_ID(_loop));
 }
 
-
-static int
-get_running_loop(asyncio_state *state, PyObject **loop)
-{
-    PyObject *rl;
-
-    PyThreadState *ts = _PyThreadState_GET();
-    uint64_t ts_id = PyThreadState_GetID(ts);
-    if (state->cached_running_loop_tsid == ts_id &&
-        state->cached_running_loop != NULL)
-    {
-        // Fast path, check the cache.
-        rl = state->cached_running_loop;
-    }
-    else {
-        PyObject *ts_dict = _PyThreadState_GetDict(ts);  // borrowed
-        if (ts_dict == NULL) {
-            goto not_found;
-        }
-
-        rl = PyDict_GetItemWithError(
-            ts_dict, &_Py_ID(__asyncio_running_event_loop__));  // borrowed
-        if (rl == NULL) {
-            if (PyErr_Occurred()) {
-                goto error;
-            }
-            else {
-                goto not_found;
-            }
-        }
-
-        // TODO GH-121621: This should be moved to PyThreadState
-        // for easier and quicker access.
-        state->cached_running_loop = rl;
-        state->cached_running_loop_tsid = ts_id;
-    }
-
-
-    if (rl == Py_None) {
-        goto not_found;
-    }
-
-    *loop = Py_NewRef(rl);
-    return 0;
-
-not_found:
-    *loop = NULL;
-    return 0;
-
-error:
-    *loop = NULL;
-    return -1;
-}
-
-
-static int
-set_running_loop(asyncio_state *state, PyObject *loop)
-{
-    PyObject *ts_dict = NULL;
-
-    PyThreadState *tstate = _PyThreadState_GET();
-    if (tstate != NULL) {
-        ts_dict = _PyThreadState_GetDict(tstate);  // borrowed
-    }
-
-    if (ts_dict == NULL) {
-        PyErr_SetString(
-            PyExc_RuntimeError, "thread-local storage is not available");
-        return -1;
-    }
-    if (PyDict_SetItem(
-            ts_dict, &_Py_ID(__asyncio_running_event_loop__), loop) < 0)
-    {
-        return -1;
-    }
-
-
-    // TODO GH-121621: This should be moved to PyThreadState
-    // for easier and quicker access.
-    state->cached_running_loop = loop; // borrowed, kept alive by ts_dict
-    state->cached_running_loop_tsid = PyThreadState_GetID(tstate);
-
-    return 0;
-}
-
-
 static PyObject *
 get_event_loop(asyncio_state *state)
 {
     PyObject *loop;
     PyObject *policy;
 
-    if (get_running_loop(state, &loop)) {
-        return NULL;
-    }
+    PyThreadState *ts = _PyThreadState_GET();
+    loop = Py_XNewRef(ts->asyncio_running_loop);
+
     if (loop != NULL) {
         return loop;
     }
@@ -3278,11 +3189,8 @@ static PyObject *
 _asyncio__get_running_loop_impl(PyObject *module)
 /*[clinic end generated code: output=b4390af721411a0a input=0a21627e25a4bd43]*/
 {
-    PyObject *loop;
-    asyncio_state *state = get_asyncio_state(module);
-    if (get_running_loop(state, &loop)) {
-        return NULL;
-    }
+    PyThreadState *ts = _PyThreadState_GET();
+    PyObject *loop = Py_XNewRef(ts->asyncio_running_loop);
     if (loop == NULL) {
         /* There's no currently running event loop */
         Py_RETURN_NONE;
@@ -3305,10 +3213,11 @@ static PyObject *
 _asyncio__set_running_loop(PyObject *module, PyObject *loop)
 /*[clinic end generated code: output=ae56bf7a28ca189a input=4c9720233d606604]*/
 {
-    asyncio_state *state = get_asyncio_state(module);
-    if (set_running_loop(state, loop)) {
-        return NULL;
+    PyThreadState *ts = _PyThreadState_GET();
+    if (loop == Py_None) {
+        loop = NULL;
     }
+    Py_XSETREF(ts->asyncio_running_loop, Py_XNewRef(loop));
     Py_RETURN_NONE;
 }
 
@@ -3346,14 +3255,13 @@ _asyncio_get_running_loop_impl(PyObject *module)
 /*[clinic end generated code: output=c247b5f9e529530e input=2a3bf02ba39f173d]*/
 {
     PyObject *loop;
-    asyncio_state *state = get_asyncio_state(module);
-    if (get_running_loop(state, &loop)) {
-        return NULL;
-    }
+    PyThreadState *ts = _PyThreadState_GET();
+    loop = Py_XNewRef(ts->asyncio_running_loop);
     if (loop == NULL) {
         /* There's no currently running event loop */
         PyErr_SetString(
             PyExc_RuntimeError, "no running event loop");
+        return NULL;
     }
     return loop;
 }
index 602b13e18c71ae58e8a5e8479309c1a0ea5e6b7b..f77a2cc54e867a43d353c14a701ff11370f5b69d 100644 (file)
@@ -1499,6 +1499,8 @@ init_threadstate(_PyThreadStateImpl *_tstate,
     tstate->previous_executor = NULL;
     tstate->dict_global_version = 0;
 
+    tstate->asyncio_running_loop = NULL;
+
     tstate->delete_later = NULL;
 
     llist_init(&_tstate->mem_free_queue);
@@ -1700,6 +1702,8 @@ PyThreadState_Clear(PyThreadState *tstate)
 
     /* Don't clear tstate->pyframe: it is a borrowed reference */
 
+    Py_CLEAR(tstate->asyncio_running_loop);
+
     Py_CLEAR(tstate->dict);
     Py_CLEAR(tstate->async_exc);