Skip to content

Commit

Permalink
[3.13] gh-121621: Disable asyncio freelist in free-threaded build (GH…
Browse files Browse the repository at this point in the history
…-122046) (#122048)

The futureobj freelist isn't thread-safe. We intend to re-enable the
freelist in a thread-safe way for 3.14 (but not 3.13).
(cherry picked from commit 9724820)
  • Loading branch information
colesbury authored Jul 19, 2024
1 parent bf7f4f3 commit f3c79cb
Showing 1 changed file with 17 additions and 5 deletions.
22 changes: 17 additions & 5 deletions Modules/_asynciomodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,10 @@ typedef struct {
/* Counter for autogenerated Task names */
uint64_t task_name_counter;

#ifndef Py_GIL_DISABLED
futureiterobject *fi_freelist;
Py_ssize_t fi_freelist_len;
#endif
} asyncio_state;

static inline asyncio_state *
Expand Down Expand Up @@ -1520,14 +1522,14 @@ FutureIter_dealloc(futureiterobject *it)

assert(_PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE));

PyObject *module = ((PyHeapTypeObject*)tp)->ht_module;
asyncio_state *state = NULL;

PyObject_GC_UnTrack(it);
tp->tp_clear((PyObject *)it);

#ifndef Py_GIL_DISABLED
// GH-115874: We can't use PyType_GetModuleByDef here as the type might have
// already been cleared, which is also why we must check if ht_module != NULL.
PyObject *module = ((PyHeapTypeObject*)tp)->ht_module;
asyncio_state *state = NULL;
if (module && _PyModule_GetDef(module) == &_asynciomodule) {
state = get_asyncio_state(module);
}
Expand All @@ -1538,7 +1540,9 @@ FutureIter_dealloc(futureiterobject *it)
it->future = (FutureObj*) state->fi_freelist;
state->fi_freelist = it;
}
else {
else
#endif
{
PyObject_GC_Del(it);
Py_DECREF(tp);
}
Expand Down Expand Up @@ -1742,14 +1746,17 @@ future_new_iter(PyObject *fut)
asyncio_state *state = get_asyncio_state_by_def((PyObject *)fut);
ENSURE_FUTURE_ALIVE(state, fut)

#ifndef Py_GIL_DISABLED
if (state->fi_freelist_len) {
state->fi_freelist_len--;
it = state->fi_freelist;
state->fi_freelist = (futureiterobject*) it->future;
it->future = NULL;
_Py_NewReference((PyObject*) it);
}
else {
else
#endif
{
it = PyObject_GC_New(futureiterobject, state->FutureIterType);
if (it == NULL) {
return NULL;
Expand Down Expand Up @@ -3463,6 +3470,7 @@ _asyncio_current_task_impl(PyObject *module, PyObject *loop)
static void
module_free_freelists(asyncio_state *state)
{
#ifndef Py_GIL_DISABLED
PyObject *next;
PyObject *current;

Expand All @@ -3477,6 +3485,7 @@ module_free_freelists(asyncio_state *state)
}
assert(state->fi_freelist_len == 0);
state->fi_freelist = NULL;
#endif
}

static int
Expand Down Expand Up @@ -3507,13 +3516,16 @@ module_traverse(PyObject *mod, visitproc visit, void *arg)

Py_VISIT(state->context_kwname);

#ifndef Py_GIL_DISABLED
// Visit freelist.
PyObject *next = (PyObject*) state->fi_freelist;
while (next != NULL) {
PyObject *current = next;
Py_VISIT(current);
next = (PyObject*) ((futureiterobject*) current)->future;
}
#endif

return 0;
}

Expand Down

0 comments on commit f3c79cb

Please sign in to comment.