Skip to content

Commit eac05aa

Browse files
switch to per loop current task
1 parent e1baa77 commit eac05aa

File tree

6 files changed

+78
-100
lines changed

6 files changed

+78
-100
lines changed

Include/internal/pycore_global_objects_fini_generated.h

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/internal/pycore_global_strings.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ struct _Py_global_strings {
234234
STRUCT_FOR_ID(_blksize)
235235
STRUCT_FOR_ID(_bootstrap)
236236
STRUCT_FOR_ID(_check_retval_)
237+
STRUCT_FOR_ID(_current_task)
237238
STRUCT_FOR_ID(_dealloc_warn)
238239
STRUCT_FOR_ID(_feature_version)
239240
STRUCT_FOR_ID(_field_types)

Include/internal/pycore_runtime_init_generated.h

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/internal/pycore_unicodeobject_generated.h

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/asyncio/tasks.py

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,11 @@ def current_task(loop=None):
3838
"""Return a currently executed task."""
3939
if loop is None:
4040
loop = events.get_running_loop()
41-
return _current_tasks.get(loop)
41+
42+
try:
43+
return loop._current_task
44+
except AttributeError:
45+
return None
4246

4347

4448
def all_tasks(loop=None):
@@ -1024,10 +1028,6 @@ def factory(loop, coro, *, name=None, context=None):
10241028
_scheduled_tasks = weakref.WeakSet()
10251029
_eager_tasks = set()
10261030

1027-
# Dictionary containing tasks that are currently active in
1028-
# all running event loops. {EventLoop: Task}
1029-
_current_tasks = {}
1030-
10311031

10321032
def _register_task(task):
10331033
"""Register an asyncio Task scheduled to run on an event loop."""
@@ -1040,29 +1040,32 @@ def _register_eager_task(task):
10401040

10411041

10421042
def _enter_task(loop, task):
1043-
current_task = _current_tasks.get(loop)
1044-
if current_task is not None:
1045-
raise RuntimeError(f"Cannot enter into task {task!r} while another "
1046-
f"task {current_task!r} is being executed.")
1047-
_current_tasks[loop] = task
1043+
try:
1044+
if loop._current_task is not None:
1045+
raise RuntimeError(f"Cannot enter into task {task!r} while another "
1046+
f"task {loop._current_task!r} is being executed.")
1047+
except AttributeError:
1048+
pass
1049+
loop._current_task = task
10481050

10491051

10501052
def _leave_task(loop, task):
1051-
current_task = _current_tasks.get(loop)
1052-
if current_task is not task:
1053-
raise RuntimeError(f"Leaving task {task!r} does not match "
1054-
f"the current task {current_task!r}.")
1055-
del _current_tasks[loop]
1053+
try:
1054+
if loop._current_task is not task:
1055+
raise RuntimeError(f"Leaving task {task!r} does not match "
1056+
f"the current task {loop._current_task!r}.")
1057+
except AttributeError:
1058+
pass
1059+
loop._current_task = None
10561060

10571061

10581062
def _swap_current_task(loop, task):
1059-
prev_task = _current_tasks.get(loop)
1060-
if task is None:
1061-
del _current_tasks[loop]
1062-
else:
1063-
_current_tasks[loop] = task
1064-
return prev_task
1065-
1063+
try:
1064+
prev_task = loop._current_task
1065+
loop._current_task = task
1066+
return prev_task
1067+
except AttributeError:
1068+
loop._current_task = task
10661069

10671070
def _unregister_task(task):
10681071
"""Unregister a completed, scheduled Task."""
@@ -1088,7 +1091,7 @@ def _unregister_eager_task(task):
10881091
from _asyncio import (_register_task, _register_eager_task,
10891092
_unregister_task, _unregister_eager_task,
10901093
_enter_task, _leave_task, _swap_current_task,
1091-
_scheduled_tasks, _eager_tasks, _current_tasks,
1094+
_scheduled_tasks, _eager_tasks,
10921095
current_task, all_tasks)
10931096
except ImportError:
10941097
pass

Modules/_asynciomodule.c

Lines changed: 45 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,6 @@ typedef struct {
9797
PyObject *asyncio_mod;
9898
PyObject *context_kwname;
9999

100-
/* Dictionary containing tasks that are currently active in
101-
all running event loops. {EventLoop: Task} */
102-
PyObject *current_tasks;
103-
104100
/* WeakSet containing scheduled 3rd party tasks which don't
105101
inherit from native asyncio.Task */
106102
PyObject *non_asyncio_tasks;
@@ -1926,11 +1922,10 @@ static int
19261922
enter_task(asyncio_state *state, PyObject *loop, PyObject *task)
19271923
{
19281924
PyObject *item;
1929-
int res = PyDict_SetDefaultRef(state->current_tasks, loop, task, &item);
1930-
if (res < 0) {
1925+
if (PyObject_GetOptionalAttr(loop, &_Py_ID(_current_task), &item) < 0) {
19311926
return -1;
19321927
}
1933-
else if (res == 1) {
1928+
if (item != NULL && item != Py_None) {
19341929
PyErr_Format(
19351930
PyExc_RuntimeError,
19361931
"Cannot enter into task %R while another " \
@@ -1939,84 +1934,63 @@ enter_task(asyncio_state *state, PyObject *loop, PyObject *task)
19391934
Py_DECREF(item);
19401935
return -1;
19411936
}
1942-
Py_DECREF(item);
1943-
return 0;
1944-
}
1945-
1946-
static int
1947-
err_leave_task(PyObject *item, PyObject *task)
1948-
{
1949-
PyErr_Format(
1950-
PyExc_RuntimeError,
1951-
"Leaving task %R does not match the current task %R.",
1952-
task, item);
1953-
return -1;
1954-
}
19551937

1956-
static int
1957-
leave_task_predicate(PyObject *item, void *task)
1958-
{
1959-
if (item != task) {
1960-
return err_leave_task(item, (PyObject *)task);
1938+
if (PyObject_SetAttr(loop, &_Py_ID(_current_task), task) < 0) {
1939+
return -1;
19611940
}
1962-
return 1;
1941+
return 0;
19631942
}
19641943

19651944
static int
19661945
leave_task(asyncio_state *state, PyObject *loop, PyObject *task)
1967-
/*[clinic end generated code: output=0ebf6db4b858fb41 input=51296a46313d1ad8]*/
19681946
{
1969-
int res = _PyDict_DelItemIf(state->current_tasks, loop,
1970-
leave_task_predicate, task);
1971-
if (res == 0) {
1972-
// task was not found
1973-
return err_leave_task(Py_None, task);
1947+
PyObject *item;
1948+
if (PyObject_GetOptionalAttr(loop, &_Py_ID(_current_task), &item) < 0) {
1949+
return -1;
19741950
}
1975-
return res;
1976-
}
19771951

1978-
static PyObject *
1979-
swap_current_task_lock_held(PyDictObject *current_tasks, PyObject *loop,
1980-
Py_hash_t hash, PyObject *task)
1981-
{
1982-
PyObject *prev_task;
1983-
if (_PyDict_GetItemRef_KnownHash_LockHeld(current_tasks, loop, hash, &prev_task) < 0) {
1984-
return NULL;
1952+
if (item == NULL || item == Py_None) {
1953+
// current task is not set
1954+
PyErr_Format(PyExc_RuntimeError,
1955+
"Leaving task %R does not match the current task %R.",
1956+
task, Py_None);
1957+
return -1;
19851958
}
1986-
if (_PyDict_SetItem_KnownHash_LockHeld(current_tasks, loop, task, hash) < 0) {
1987-
Py_XDECREF(prev_task);
1988-
return NULL;
1959+
1960+
if (item != task) {
1961+
// different task
1962+
PyErr_Format(PyExc_RuntimeError,
1963+
"Leaving task %R does not match the current task %R.",
1964+
task, item);
1965+
Py_DECREF(item);
1966+
return -1;
19891967
}
1990-
if (prev_task == NULL) {
1991-
Py_RETURN_NONE;
1968+
Py_DECREF(item);
1969+
1970+
if (PyObject_SetAttr(loop, &_Py_ID(_current_task), Py_None) < 0) {
1971+
return -1;
19921972
}
1993-
return prev_task;
1973+
return 0;
19941974
}
19951975

1976+
19961977
static PyObject *
19971978
swap_current_task(asyncio_state *state, PyObject *loop, PyObject *task)
19981979
{
19991980
PyObject *prev_task;
20001981

2001-
if (task == Py_None) {
2002-
if (PyDict_Pop(state->current_tasks, loop, &prev_task) < 0) {
2003-
return NULL;
2004-
}
2005-
if (prev_task == NULL) {
2006-
Py_RETURN_NONE;
2007-
}
2008-
return prev_task;
1982+
if (PyObject_GetOptionalAttr(loop, &_Py_ID(_current_task), &prev_task) < 0) {
1983+
return NULL;
20091984
}
20101985

2011-
Py_hash_t hash = PyObject_Hash(loop);
2012-
if (hash == -1) {
1986+
if (PyObject_SetAttr(loop, &_Py_ID(_current_task), task) < 0) {
1987+
Py_XDECREF(prev_task);
20131988
return NULL;
20141989
}
20151990

2016-
PyDictObject *current_tasks = (PyDictObject *)state->current_tasks;
2017-
Py_BEGIN_CRITICAL_SECTION(current_tasks);
2018-
prev_task = swap_current_task_lock_held(current_tasks, loop, hash, task);
2019-
Py_END_CRITICAL_SECTION();
1991+
if (prev_task == NULL) {
1992+
Py_RETURN_NONE;
1993+
}
20201994
return prev_task;
20211995
}
20221996

@@ -3503,9 +3477,6 @@ static PyObject *
35033477
_asyncio_current_task_impl(PyObject *module, PyObject *loop)
35043478
/*[clinic end generated code: output=fe15ac331a7f981a input=58910f61a5627112]*/
35053479
{
3506-
PyObject *ret;
3507-
asyncio_state *state = get_asyncio_state(module);
3508-
35093480
if (loop == Py_None) {
35103481
loop = _asyncio_get_running_loop_impl(module);
35113482
if (loop == NULL) {
@@ -3515,12 +3486,19 @@ _asyncio_current_task_impl(PyObject *module, PyObject *loop)
35153486
Py_INCREF(loop);
35163487
}
35173488

3518-
int rc = PyDict_GetItemRef(state->current_tasks, loop, &ret);
3489+
PyObject *item;
3490+
if (PyObject_GetOptionalAttr(loop, &_Py_ID(_current_task), &item) < 0) {
3491+
Py_DECREF(loop);
3492+
return NULL;
3493+
}
3494+
35193495
Py_DECREF(loop);
3520-
if (rc == 0) {
3496+
3497+
if (item == NULL) {
35213498
Py_RETURN_NONE;
35223499
}
3523-
return ret;
3500+
3501+
return item;
35243502
}
35253503

35263504

@@ -3675,7 +3653,6 @@ module_traverse(PyObject *mod, visitproc visit, void *arg)
36753653

36763654
Py_VISIT(state->non_asyncio_tasks);
36773655
Py_VISIT(state->eager_tasks);
3678-
Py_VISIT(state->current_tasks);
36793656
Py_VISIT(state->iscoroutine_typecache);
36803657

36813658
Py_VISIT(state->context_kwname);
@@ -3706,7 +3683,6 @@ module_clear(PyObject *mod)
37063683

37073684
Py_CLEAR(state->non_asyncio_tasks);
37083685
Py_CLEAR(state->eager_tasks);
3709-
Py_CLEAR(state->current_tasks);
37103686
Py_CLEAR(state->iscoroutine_typecache);
37113687

37123688
Py_CLEAR(state->context_kwname);
@@ -3735,10 +3711,6 @@ module_init(asyncio_state *state)
37353711
goto fail;
37363712
}
37373713

3738-
state->current_tasks = PyDict_New();
3739-
if (state->current_tasks == NULL) {
3740-
goto fail;
3741-
}
37423714

37433715
state->iscoroutine_typecache = PySet_New(NULL);
37443716
if (state->iscoroutine_typecache == NULL) {
@@ -3872,10 +3844,6 @@ module_exec(PyObject *mod)
38723844
return -1;
38733845
}
38743846

3875-
if (PyModule_AddObjectRef(mod, "_current_tasks", state->current_tasks) < 0) {
3876-
return -1;
3877-
}
3878-
38793847

38803848
return 0;
38813849
}

0 commit comments

Comments
 (0)