Skip to content

Commit fb554ad

Browse files
gh-140414: streamline thread state access in asyncio (#142742)
1 parent 15c9d90 commit fb554ad

File tree

3 files changed

+36
-33
lines changed

3 files changed

+36
-33
lines changed

Include/internal/pycore_context.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,5 +55,8 @@ struct _pycontexttokenobject {
5555
// Export for '_testcapi' shared extension
5656
PyAPI_FUNC(PyObject*) _PyContext_NewHamtForTests(void);
5757

58+
PyAPI_FUNC(int) _PyContext_Enter(PyThreadState *ts, PyObject *octx);
59+
PyAPI_FUNC(int) _PyContext_Exit(PyThreadState *ts, PyObject *octx);
60+
5861

5962
#endif /* !Py_INTERNAL_CONTEXT_H */

Modules/_asynciomodule.c

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2076,8 +2076,8 @@ class _asyncio.Task "TaskObj *" "&Task_Type"
20762076

20772077
static int task_call_step_soon(asyncio_state *state, TaskObj *, PyObject *);
20782078
static PyObject *task_wakeup(PyObject *op, PyObject *arg);
2079-
static PyObject * task_step(asyncio_state *, TaskObj *, PyObject *);
2080-
static int task_eager_start(asyncio_state *state, TaskObj *task);
2079+
static PyObject *task_step(asyncio_state *, TaskObj *, PyObject *);
2080+
static int task_eager_start(_PyThreadStateImpl *ts, asyncio_state *state, TaskObj *task);
20812081

20822082
/* ----- Task._step wrapper */
20832083

@@ -2195,15 +2195,14 @@ static PyMethodDef TaskWakeupDef = {
21952195
/* ----- Task introspection helpers */
21962196

21972197
static void
2198-
register_task(TaskObj *task)
2198+
register_task(_PyThreadStateImpl *ts, TaskObj *task)
21992199
{
22002200
if (task->task_node.next != NULL) {
22012201
// already registered
22022202
assert(task->task_node.prev != NULL);
22032203
return;
22042204
}
2205-
_PyThreadStateImpl *tstate = (_PyThreadStateImpl *) _PyThreadState_GET();
2206-
struct llist_node *head = &tstate->asyncio_tasks_head;
2205+
struct llist_node *head = &ts->asyncio_tasks_head;
22072206
llist_insert_tail(head, &task->task_node);
22082207
}
22092208

@@ -2241,10 +2240,8 @@ unregister_task(TaskObj *task)
22412240
}
22422241

22432242
static int
2244-
enter_task(PyObject *loop, PyObject *task)
2243+
enter_task(_PyThreadStateImpl *ts, PyObject *loop, PyObject *task)
22452244
{
2246-
_PyThreadStateImpl *ts = (_PyThreadStateImpl *)_PyThreadState_GET();
2247-
22482245
if (ts->asyncio_running_loop != loop) {
22492246
PyErr_Format(PyExc_RuntimeError, "loop %R is not the running loop", loop);
22502247
return -1;
@@ -2264,10 +2261,8 @@ enter_task(PyObject *loop, PyObject *task)
22642261
}
22652262

22662263
static int
2267-
leave_task(PyObject *loop, PyObject *task)
2264+
leave_task(_PyThreadStateImpl *ts, PyObject *loop, PyObject *task)
22682265
{
2269-
_PyThreadStateImpl *ts = (_PyThreadStateImpl *)_PyThreadState_GET();
2270-
22712266
if (ts->asyncio_running_loop != loop) {
22722267
PyErr_Format(PyExc_RuntimeError, "loop %R is not the running loop", loop);
22732268
return -1;
@@ -2286,10 +2281,8 @@ leave_task(PyObject *loop, PyObject *task)
22862281
}
22872282

22882283
static PyObject *
2289-
swap_current_task(PyObject *loop, PyObject *task)
2284+
swap_current_task(_PyThreadStateImpl *ts, PyObject *loop, PyObject *task)
22902285
{
2291-
_PyThreadStateImpl *ts = (_PyThreadStateImpl *)_PyThreadState_GET();
2292-
22932286
if (ts->asyncio_running_loop != loop) {
22942287
PyErr_Format(PyExc_RuntimeError, "loop %R is not the running loop", loop);
22952288
return NULL;
@@ -2384,7 +2377,7 @@ _asyncio_Task___init___impl(TaskObj *self, PyObject *coro, PyObject *loop,
23842377
if (self->task_name == NULL) {
23852378
return -1;
23862379
}
2387-
2380+
_PyThreadStateImpl *ts = (_PyThreadStateImpl *)_PyThreadState_GET();
23882381
if (eager_start) {
23892382
PyObject *res = PyObject_CallMethodNoArgs(loop, &_Py_ID(is_running));
23902383
if (res == NULL) {
@@ -2393,7 +2386,7 @@ _asyncio_Task___init___impl(TaskObj *self, PyObject *coro, PyObject *loop,
23932386
int is_loop_running = Py_IsTrue(res);
23942387
Py_DECREF(res);
23952388
if (is_loop_running) {
2396-
if (task_eager_start(state, self)) {
2389+
if (task_eager_start(ts, state, self)) {
23972390
return -1;
23982391
}
23992392
return 0;
@@ -2408,7 +2401,7 @@ _asyncio_Task___init___impl(TaskObj *self, PyObject *coro, PyObject *loop,
24082401
// works correctly in non-owning threads.
24092402
_PyObject_SetMaybeWeakref((PyObject *)self);
24102403
#endif
2411-
register_task(self);
2404+
register_task(ts, self);
24122405
return 0;
24132406
}
24142407

@@ -3452,20 +3445,22 @@ task_step(asyncio_state *state, TaskObj *task, PyObject *exc)
34523445
{
34533446
PyObject *res;
34543447

3455-
if (enter_task(task->task_loop, (PyObject*)task) < 0) {
3448+
_PyThreadStateImpl *ts = (_PyThreadStateImpl *)_PyThreadState_GET();
3449+
3450+
if (enter_task(ts, task->task_loop, (PyObject*)task) < 0) {
34563451
return NULL;
34573452
}
34583453

34593454
res = task_step_impl(state, task, exc);
34603455

34613456
if (res == NULL) {
34623457
PyObject *exc = PyErr_GetRaisedException();
3463-
leave_task(task->task_loop, (PyObject*)task);
3458+
leave_task(ts, task->task_loop, (PyObject*)task);
34643459
_PyErr_ChainExceptions1(exc);
34653460
return NULL;
34663461
}
34673462
else {
3468-
if (leave_task(task->task_loop, (PyObject*)task) < 0) {
3463+
if (leave_task(ts, task->task_loop, (PyObject*)task) < 0) {
34693464
Py_DECREF(res);
34703465
return NULL;
34713466
}
@@ -3476,20 +3471,20 @@ task_step(asyncio_state *state, TaskObj *task, PyObject *exc)
34763471
}
34773472

34783473
static int
3479-
task_eager_start(asyncio_state *state, TaskObj *task)
3474+
task_eager_start(_PyThreadStateImpl *ts, asyncio_state *state, TaskObj *task)
34803475
{
34813476
assert(task != NULL);
3482-
PyObject *prevtask = swap_current_task(task->task_loop, (PyObject *)task);
3477+
PyObject *prevtask = swap_current_task(ts, task->task_loop, (PyObject *)task);
34833478
if (prevtask == NULL) {
34843479
return -1;
34853480
}
34863481
// register the task into the linked list of tasks
34873482
// if the task completes eagerly (without suspending) then it will unregister itself
34883483
// in future_schedule_callbacks when done, otherwise
34893484
// it will continue as a regular (non-eager) asyncio task
3490-
register_task(task);
3485+
register_task(ts, task);
34913486

3492-
if (PyContext_Enter(task->task_context) == -1) {
3487+
if (_PyContext_Enter(&ts->base, task->task_context) == -1) {
34933488
Py_DECREF(prevtask);
34943489
return -1;
34953490
}
@@ -3508,7 +3503,7 @@ task_eager_start(asyncio_state *state, TaskObj *task)
35083503
Py_DECREF(stepres);
35093504
}
35103505

3511-
PyObject *curtask = swap_current_task(task->task_loop, prevtask);
3506+
PyObject *curtask = swap_current_task(ts, task->task_loop, prevtask);
35123507
Py_DECREF(prevtask);
35133508
if (curtask == NULL) {
35143509
retval = -1;
@@ -3517,7 +3512,7 @@ task_eager_start(asyncio_state *state, TaskObj *task)
35173512
Py_DECREF(curtask);
35183513
}
35193514

3520-
if (PyContext_Exit(task->task_context) == -1) {
3515+
if (_PyContext_Exit(&ts->base, task->task_context) == -1) {
35213516
retval = -1;
35223517
}
35233518

@@ -3712,7 +3707,8 @@ _asyncio__register_task_impl(PyObject *module, PyObject *task)
37123707
if (Task_Check(state, task)) {
37133708
// task is an asyncio.Task instance or subclass, use efficient
37143709
// linked-list implementation.
3715-
register_task((TaskObj *)task);
3710+
_PyThreadStateImpl *ts = (_PyThreadStateImpl *)_PyThreadState_GET();
3711+
register_task(ts, (TaskObj *)task);
37163712
Py_RETURN_NONE;
37173713
}
37183714
// As task does not inherit from asyncio.Task, fallback to less efficient
@@ -3745,7 +3741,8 @@ _asyncio__register_eager_task_impl(PyObject *module, PyObject *task)
37453741
if (Task_Check(state, task)) {
37463742
// task is an asyncio.Task instance or subclass, use efficient
37473743
// linked-list implementation.
3748-
register_task((TaskObj *)task);
3744+
_PyThreadStateImpl *ts = (_PyThreadStateImpl *)_PyThreadState_GET();
3745+
register_task(ts, (TaskObj *)task);
37493746
Py_RETURN_NONE;
37503747
}
37513748

@@ -3832,7 +3829,8 @@ static PyObject *
38323829
_asyncio__enter_task_impl(PyObject *module, PyObject *loop, PyObject *task)
38333830
/*[clinic end generated code: output=a22611c858035b73 input=de1b06dca70d8737]*/
38343831
{
3835-
if (enter_task(loop, task) < 0) {
3832+
_PyThreadStateImpl *ts = (_PyThreadStateImpl *)_PyThreadState_GET();
3833+
if (enter_task(ts, loop, task) < 0) {
38363834
return NULL;
38373835
}
38383836
Py_RETURN_NONE;
@@ -3856,7 +3854,8 @@ static PyObject *
38563854
_asyncio__leave_task_impl(PyObject *module, PyObject *loop, PyObject *task)
38573855
/*[clinic end generated code: output=0ebf6db4b858fb41 input=51296a46313d1ad8]*/
38583856
{
3859-
if (leave_task(loop, task) < 0) {
3857+
_PyThreadStateImpl *ts = (_PyThreadStateImpl *)_PyThreadState_GET();
3858+
if (leave_task(ts, loop, task) < 0) {
38603859
return NULL;
38613860
}
38623861
Py_RETURN_NONE;
@@ -3880,7 +3879,8 @@ _asyncio__swap_current_task_impl(PyObject *module, PyObject *loop,
38803879
PyObject *task)
38813880
/*[clinic end generated code: output=9f88de958df74c7e input=c9c72208d3d38b6c]*/
38823881
{
3883-
return swap_current_task(loop, task);
3882+
_PyThreadStateImpl *ts = (_PyThreadStateImpl *)_PyThreadState_GET();
3883+
return swap_current_task(ts, loop, task);
38843884
}
38853885

38863886

Python/context.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ context_switched(PyThreadState *ts)
190190
}
191191

192192

193-
static int
193+
int
194194
_PyContext_Enter(PyThreadState *ts, PyObject *octx)
195195
{
196196
ENSURE_Context(octx, -1)
@@ -220,7 +220,7 @@ PyContext_Enter(PyObject *octx)
220220
}
221221

222222

223-
static int
223+
int
224224
_PyContext_Exit(PyThreadState *ts, PyObject *octx)
225225
{
226226
ENSURE_Context(octx, -1)

0 commit comments

Comments
 (0)