Skip to content

Commit 69c68de

Browse files
gh-121621: Move asyncio running loop to thread state (GH-121695)
1 parent 8f25321 commit 69c68de

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
@@ -77,7 +77,6 @@ struct _Py_global_strings {
7777
STRUCT_FOR_ID(__annotate__)
7878
STRUCT_FOR_ID(__annotations__)
7979
STRUCT_FOR_ID(__args__)
80-
STRUCT_FOR_ID(__asyncio_running_event_loop__)
8180
STRUCT_FOR_ID(__await__)
8281
STRUCT_FOR_ID(__bases__)
8382
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
@@ -135,9 +135,6 @@ typedef struct {
135135
/* Imports from traceback. */
136136
PyObject *traceback_extract_stack;
137137

138-
PyObject *cached_running_loop; // Borrowed reference
139-
volatile uint64_t cached_running_loop_tsid;
140-
141138
/* Counter for autogenerated Task names */
142139
uint64_t task_name_counter;
143140

@@ -321,101 +318,15 @@ get_future_loop(asyncio_state *state, PyObject *fut)
321318
return PyObject_GetAttr(fut, &_Py_ID(_loop));
322319
}
323320

324-
325-
static int
326-
get_running_loop(asyncio_state *state, PyObject **loop)
327-
{
328-
PyObject *rl;
329-
330-
PyThreadState *ts = _PyThreadState_GET();
331-
uint64_t ts_id = PyThreadState_GetID(ts);
332-
if (state->cached_running_loop_tsid == ts_id &&
333-
state->cached_running_loop != NULL)
334-
{
335-
// Fast path, check the cache.
336-
rl = state->cached_running_loop;
337-
}
338-
else {
339-
PyObject *ts_dict = _PyThreadState_GetDict(ts); // borrowed
340-
if (ts_dict == NULL) {
341-
goto not_found;
342-
}
343-
344-
rl = PyDict_GetItemWithError(
345-
ts_dict, &_Py_ID(__asyncio_running_event_loop__)); // borrowed
346-
if (rl == NULL) {
347-
if (PyErr_Occurred()) {
348-
goto error;
349-
}
350-
else {
351-
goto not_found;
352-
}
353-
}
354-
355-
// TODO GH-121621: This should be moved to PyThreadState
356-
// for easier and quicker access.
357-
state->cached_running_loop = rl;
358-
state->cached_running_loop_tsid = ts_id;
359-
}
360-
361-
362-
if (rl == Py_None) {
363-
goto not_found;
364-
}
365-
366-
*loop = Py_NewRef(rl);
367-
return 0;
368-
369-
not_found:
370-
*loop = NULL;
371-
return 0;
372-
373-
error:
374-
*loop = NULL;
375-
return -1;
376-
}
377-
378-
379-
static int
380-
set_running_loop(asyncio_state *state, PyObject *loop)
381-
{
382-
PyObject *ts_dict = NULL;
383-
384-
PyThreadState *tstate = _PyThreadState_GET();
385-
if (tstate != NULL) {
386-
ts_dict = _PyThreadState_GetDict(tstate); // borrowed
387-
}
388-
389-
if (ts_dict == NULL) {
390-
PyErr_SetString(
391-
PyExc_RuntimeError, "thread-local storage is not available");
392-
return -1;
393-
}
394-
if (PyDict_SetItem(
395-
ts_dict, &_Py_ID(__asyncio_running_event_loop__), loop) < 0)
396-
{
397-
return -1;
398-
}
399-
400-
401-
// TODO GH-121621: This should be moved to PyThreadState
402-
// for easier and quicker access.
403-
state->cached_running_loop = loop; // borrowed, kept alive by ts_dict
404-
state->cached_running_loop_tsid = PyThreadState_GetID(tstate);
405-
406-
return 0;
407-
}
408-
409-
410321
static PyObject *
411322
get_event_loop(asyncio_state *state)
412323
{
413324
PyObject *loop;
414325
PyObject *policy;
415326

416-
if (get_running_loop(state, &loop)) {
417-
return NULL;
418-
}
327+
PyThreadState *ts = _PyThreadState_GET();
328+
loop = Py_XNewRef(ts->asyncio_running_loop);
329+
419330
if (loop != NULL) {
420331
return loop;
421332
}
@@ -3367,11 +3278,8 @@ static PyObject *
33673278
_asyncio__get_running_loop_impl(PyObject *module)
33683279
/*[clinic end generated code: output=b4390af721411a0a input=0a21627e25a4bd43]*/
33693280
{
3370-
PyObject *loop;
3371-
asyncio_state *state = get_asyncio_state(module);
3372-
if (get_running_loop(state, &loop)) {
3373-
return NULL;
3374-
}
3281+
PyThreadState *ts = _PyThreadState_GET();
3282+
PyObject *loop = Py_XNewRef(ts->asyncio_running_loop);
33753283
if (loop == NULL) {
33763284
/* There's no currently running event loop */
33773285
Py_RETURN_NONE;
@@ -3394,10 +3302,11 @@ static PyObject *
33943302
_asyncio__set_running_loop(PyObject *module, PyObject *loop)
33953303
/*[clinic end generated code: output=ae56bf7a28ca189a input=4c9720233d606604]*/
33963304
{
3397-
asyncio_state *state = get_asyncio_state(module);
3398-
if (set_running_loop(state, loop)) {
3399-
return NULL;
3305+
PyThreadState *ts = _PyThreadState_GET();
3306+
if (loop == Py_None) {
3307+
loop = NULL;
34003308
}
3309+
Py_XSETREF(ts->asyncio_running_loop, Py_XNewRef(loop));
34013310
Py_RETURN_NONE;
34023311
}
34033312

@@ -3435,14 +3344,13 @@ _asyncio_get_running_loop_impl(PyObject *module)
34353344
/*[clinic end generated code: output=c247b5f9e529530e input=2a3bf02ba39f173d]*/
34363345
{
34373346
PyObject *loop;
3438-
asyncio_state *state = get_asyncio_state(module);
3439-
if (get_running_loop(state, &loop)) {
3440-
return NULL;
3441-
}
3347+
PyThreadState *ts = _PyThreadState_GET();
3348+
loop = Py_XNewRef(ts->asyncio_running_loop);
34423349
if (loop == NULL) {
34433350
/* There's no currently running event loop */
34443351
PyErr_SetString(
34453352
PyExc_RuntimeError, "no running event loop");
3353+
return NULL;
34463354
}
34473355
return loop;
34483356
}

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)