Skip to content

Commit 06d76c4

Browse files
[3.13] gh-121621: Move asyncio running loop to thread state (GH-121695) (GH-121864)
gh-121621: Move asyncio running loop to thread state (GH-121695) (cherry picked from commit 69c68de) Co-authored-by: Ken Jin <[email protected]>
1 parent 54db42f commit 06d76c4

7 files changed

+18
-111
lines changed

Include/cpython/pystate.h

+2
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ struct _ts {
6868
pycore_ceval.h. */
6969
uintptr_t eval_breaker;
7070

71+
PyObject *asyncio_running_loop; // Strong reference
72+
7173
struct {
7274
/* Has been initialized to a safe state.
7375

Include/internal/pycore_global_objects_fini_generated.h

-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/internal/pycore_global_strings.h

-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,6 @@ struct _Py_global_strings {
7575
STRUCT_FOR_ID(__anext__)
7676
STRUCT_FOR_ID(__annotations__)
7777
STRUCT_FOR_ID(__args__)
78-
STRUCT_FOR_ID(__asyncio_running_event_loop__)
7978
STRUCT_FOR_ID(__await__)
8079
STRUCT_FOR_ID(__bases__)
8180
STRUCT_FOR_ID(__bool__)

Include/internal/pycore_runtime_init_generated.h

-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/internal/pycore_unicodeobject_generated.h

-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Modules/_asynciomodule.c

+12-104
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,6 @@ typedef struct {
6868
/* Imports from traceback. */
6969
PyObject *traceback_extract_stack;
7070

71-
PyObject *cached_running_loop; // Borrowed reference
72-
volatile uint64_t cached_running_loop_tsid;
73-
7471
/* Counter for autogenerated Task names */
7572
uint64_t task_name_counter;
7673

@@ -262,101 +259,15 @@ get_future_loop(asyncio_state *state, PyObject *fut)
262259
return PyObject_GetAttr(fut, &_Py_ID(_loop));
263260
}
264261

265-
266-
static int
267-
get_running_loop(asyncio_state *state, PyObject **loop)
268-
{
269-
PyObject *rl;
270-
271-
PyThreadState *ts = _PyThreadState_GET();
272-
uint64_t ts_id = PyThreadState_GetID(ts);
273-
if (state->cached_running_loop_tsid == ts_id &&
274-
state->cached_running_loop != NULL)
275-
{
276-
// Fast path, check the cache.
277-
rl = state->cached_running_loop;
278-
}
279-
else {
280-
PyObject *ts_dict = _PyThreadState_GetDict(ts); // borrowed
281-
if (ts_dict == NULL) {
282-
goto not_found;
283-
}
284-
285-
rl = PyDict_GetItemWithError(
286-
ts_dict, &_Py_ID(__asyncio_running_event_loop__)); // borrowed
287-
if (rl == NULL) {
288-
if (PyErr_Occurred()) {
289-
goto error;
290-
}
291-
else {
292-
goto not_found;
293-
}
294-
}
295-
296-
// TODO GH-121621: This should be moved to PyThreadState
297-
// for easier and quicker access.
298-
state->cached_running_loop = rl;
299-
state->cached_running_loop_tsid = ts_id;
300-
}
301-
302-
303-
if (rl == Py_None) {
304-
goto not_found;
305-
}
306-
307-
*loop = Py_NewRef(rl);
308-
return 0;
309-
310-
not_found:
311-
*loop = NULL;
312-
return 0;
313-
314-
error:
315-
*loop = NULL;
316-
return -1;
317-
}
318-
319-
320-
static int
321-
set_running_loop(asyncio_state *state, PyObject *loop)
322-
{
323-
PyObject *ts_dict = NULL;
324-
325-
PyThreadState *tstate = _PyThreadState_GET();
326-
if (tstate != NULL) {
327-
ts_dict = _PyThreadState_GetDict(tstate); // borrowed
328-
}
329-
330-
if (ts_dict == NULL) {
331-
PyErr_SetString(
332-
PyExc_RuntimeError, "thread-local storage is not available");
333-
return -1;
334-
}
335-
if (PyDict_SetItem(
336-
ts_dict, &_Py_ID(__asyncio_running_event_loop__), loop) < 0)
337-
{
338-
return -1;
339-
}
340-
341-
342-
// TODO GH-121621: This should be moved to PyThreadState
343-
// for easier and quicker access.
344-
state->cached_running_loop = loop; // borrowed, kept alive by ts_dict
345-
state->cached_running_loop_tsid = PyThreadState_GetID(tstate);
346-
347-
return 0;
348-
}
349-
350-
351262
static PyObject *
352263
get_event_loop(asyncio_state *state)
353264
{
354265
PyObject *loop;
355266
PyObject *policy;
356267

357-
if (get_running_loop(state, &loop)) {
358-
return NULL;
359-
}
268+
PyThreadState *ts = _PyThreadState_GET();
269+
loop = Py_XNewRef(ts->asyncio_running_loop);
270+
360271
if (loop != NULL) {
361272
return loop;
362273
}
@@ -3278,11 +3189,8 @@ static PyObject *
32783189
_asyncio__get_running_loop_impl(PyObject *module)
32793190
/*[clinic end generated code: output=b4390af721411a0a input=0a21627e25a4bd43]*/
32803191
{
3281-
PyObject *loop;
3282-
asyncio_state *state = get_asyncio_state(module);
3283-
if (get_running_loop(state, &loop)) {
3284-
return NULL;
3285-
}
3192+
PyThreadState *ts = _PyThreadState_GET();
3193+
PyObject *loop = Py_XNewRef(ts->asyncio_running_loop);
32863194
if (loop == NULL) {
32873195
/* There's no currently running event loop */
32883196
Py_RETURN_NONE;
@@ -3305,10 +3213,11 @@ static PyObject *
33053213
_asyncio__set_running_loop(PyObject *module, PyObject *loop)
33063214
/*[clinic end generated code: output=ae56bf7a28ca189a input=4c9720233d606604]*/
33073215
{
3308-
asyncio_state *state = get_asyncio_state(module);
3309-
if (set_running_loop(state, loop)) {
3310-
return NULL;
3216+
PyThreadState *ts = _PyThreadState_GET();
3217+
if (loop == Py_None) {
3218+
loop = NULL;
33113219
}
3220+
Py_XSETREF(ts->asyncio_running_loop, Py_XNewRef(loop));
33123221
Py_RETURN_NONE;
33133222
}
33143223

@@ -3346,14 +3255,13 @@ _asyncio_get_running_loop_impl(PyObject *module)
33463255
/*[clinic end generated code: output=c247b5f9e529530e input=2a3bf02ba39f173d]*/
33473256
{
33483257
PyObject *loop;
3349-
asyncio_state *state = get_asyncio_state(module);
3350-
if (get_running_loop(state, &loop)) {
3351-
return NULL;
3352-
}
3258+
PyThreadState *ts = _PyThreadState_GET();
3259+
loop = Py_XNewRef(ts->asyncio_running_loop);
33533260
if (loop == NULL) {
33543261
/* There's no currently running event loop */
33553262
PyErr_SetString(
33563263
PyExc_RuntimeError, "no running event loop");
3264+
return NULL;
33573265
}
33583266
return loop;
33593267
}

Python/pystate.c

+4
Original file line numberDiff line numberDiff line change
@@ -1499,6 +1499,8 @@ init_threadstate(_PyThreadStateImpl *_tstate,
14991499
tstate->previous_executor = NULL;
15001500
tstate->dict_global_version = 0;
15011501

1502+
tstate->asyncio_running_loop = NULL;
1503+
15021504
tstate->delete_later = NULL;
15031505

15041506
llist_init(&_tstate->mem_free_queue);
@@ -1700,6 +1702,8 @@ PyThreadState_Clear(PyThreadState *tstate)
17001702

17011703
/* Don't clear tstate->pyframe: it is a borrowed reference */
17021704

1705+
Py_CLEAR(tstate->asyncio_running_loop);
1706+
17031707
Py_CLEAR(tstate->dict);
17041708
Py_CLEAR(tstate->async_exc);
17051709

0 commit comments

Comments
 (0)