Skip to content

Commit 5d6861a

Browse files
gh-121621: Use PyMutex for writes to asyncio state (#121622)
Co-authored-by: Kumar Aditya <[email protected]>
1 parent bb802db commit 5d6861a

File tree

1 file changed

+29
-1
lines changed

1 file changed

+29
-1
lines changed

Modules/_asynciomodule.c

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,21 @@ typedef struct {
7777

7878
#define FI_FREELIST_MAXLEN 255
7979

80+
#ifdef Py_GIL_DISABLED
81+
# define ASYNCIO_STATE_LOCK(state) PyMutex_Lock(&state->mutex)
82+
# define ASYNCIO_STATE_UNLOCK(state) PyMutex_Unlock(&state->mutex)
83+
#else
84+
# define ASYNCIO_STATE_LOCK(state) ((void)state)
85+
# define ASYNCIO_STATE_UNLOCK(state) ((void)state)
86+
#endif
87+
8088
typedef struct futureiterobject futureiterobject;
8189

8290
/* State of the _asyncio module */
8391
typedef struct {
92+
#ifdef Py_GIL_DISABLED
93+
PyMutex mutex;
94+
#endif
8495
PyTypeObject *FutureIterType;
8596
PyTypeObject *TaskStepMethWrapper_Type;
8697
PyTypeObject *FutureType;
@@ -341,6 +352,8 @@ get_running_loop(asyncio_state *state, PyObject **loop)
341352
}
342353
}
343354

355+
// TODO GH-121621: This should be moved to PyThreadState
356+
// for easier and quicker access.
344357
state->cached_running_loop = rl;
345358
state->cached_running_loop_tsid = ts_id;
346359
}
@@ -384,6 +397,9 @@ set_running_loop(asyncio_state *state, PyObject *loop)
384397
return -1;
385398
}
386399

400+
401+
// TODO GH-121621: This should be moved to PyThreadState
402+
// for easier and quicker access.
387403
state->cached_running_loop = loop; // borrowed, kept alive by ts_dict
388404
state->cached_running_loop_tsid = PyThreadState_GetID(tstate);
389405

@@ -1664,6 +1680,7 @@ FutureIter_dealloc(futureiterobject *it)
16641680
state = get_asyncio_state(module);
16651681
}
16661682

1683+
// TODO GH-121621: This should be moved to thread state as well.
16671684
if (state && state->fi_freelist_len < FI_FREELIST_MAXLEN) {
16681685
state->fi_freelist_len++;
16691686
it->future = (FutureObj*) state->fi_freelist;
@@ -2015,10 +2032,12 @@ static PyMethodDef TaskWakeupDef = {
20152032
static void
20162033
register_task(asyncio_state *state, TaskObj *task)
20172034
{
2035+
ASYNCIO_STATE_LOCK(state);
20182036
assert(Task_Check(state, task));
20192037
assert(task != &state->asyncio_tasks.tail);
20202038
if (task->next != NULL) {
20212039
// already registered
2040+
ASYNCIO_STATE_UNLOCK(state);
20222041
return;
20232042
}
20242043
assert(task->prev == NULL);
@@ -2027,6 +2046,7 @@ register_task(asyncio_state *state, TaskObj *task)
20272046
task->next = state->asyncio_tasks.head;
20282047
state->asyncio_tasks.head->prev = task;
20292048
state->asyncio_tasks.head = task;
2049+
ASYNCIO_STATE_UNLOCK(state);
20302050
}
20312051

20322052
static int
@@ -2038,12 +2058,14 @@ register_eager_task(asyncio_state *state, PyObject *task)
20382058
static void
20392059
unregister_task(asyncio_state *state, TaskObj *task)
20402060
{
2061+
ASYNCIO_STATE_LOCK(state);
20412062
assert(Task_Check(state, task));
20422063
assert(task != &state->asyncio_tasks.tail);
20432064
if (task->next == NULL) {
20442065
// not registered
20452066
assert(task->prev == NULL);
20462067
assert(state->asyncio_tasks.head != task);
2068+
ASYNCIO_STATE_UNLOCK(state);
20472069
return;
20482070
}
20492071
task->next->prev = task->prev;
@@ -2056,6 +2078,7 @@ unregister_task(asyncio_state *state, TaskObj *task)
20562078
task->next = NULL;
20572079
task->prev = NULL;
20582080
assert(state->asyncio_tasks.head != task);
2081+
ASYNCIO_STATE_UNLOCK(state);
20592082
}
20602083

20612084
static int
@@ -2210,7 +2233,12 @@ _asyncio_Task___init___impl(TaskObj *self, PyObject *coro, PyObject *loop,
22102233
// optimization: defer task name formatting
22112234
// store the task counter as PyLong in the name
22122235
// for deferred formatting in get_name
2213-
name = PyLong_FromUnsignedLongLong(++state->task_name_counter);
2236+
#ifdef Py_GIL_DISABLED
2237+
unsigned long long counter = _Py_atomic_add_uint64(&state->task_name_counter, 1) + 1;
2238+
#else
2239+
unsigned long long counter = ++state->task_name_counter;
2240+
#endif
2241+
name = PyLong_FromUnsignedLongLong(counter);
22142242
} else if (!PyUnicode_CheckExact(name)) {
22152243
name = PyObject_Str(name);
22162244
} else {

0 commit comments

Comments
 (0)