gh-121621: Disable asyncio freelist in free-threaded build (#122046)

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).
This commit is contained in:
Sam Gross 2024-07-19 15:26:29 -04:00 committed by GitHub
parent e059aa6b01
commit 97248204a1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 17 additions and 5 deletions

View File

@ -138,8 +138,10 @@ typedef struct {
/* Counter for autogenerated Task names */ /* Counter for autogenerated Task names */
uint64_t task_name_counter; uint64_t task_name_counter;
#ifndef Py_GIL_DISABLED
futureiterobject *fi_freelist; futureiterobject *fi_freelist;
Py_ssize_t fi_freelist_len; Py_ssize_t fi_freelist_len;
#endif
/* Linked-list of all tasks which are instances of asyncio.Task or subclasses /* Linked-list of all tasks which are instances of asyncio.Task or subclasses
of it. Third party tasks implementations which don't inherit from of it. Third party tasks implementations which don't inherit from
@ -1579,14 +1581,14 @@ FutureIter_dealloc(futureiterobject *it)
assert(_PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE)); assert(_PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE));
PyObject *module = ((PyHeapTypeObject*)tp)->ht_module;
asyncio_state *state = NULL;
PyObject_GC_UnTrack(it); PyObject_GC_UnTrack(it);
tp->tp_clear((PyObject *)it); tp->tp_clear((PyObject *)it);
#ifndef Py_GIL_DISABLED
// GH-115874: We can't use PyType_GetModuleByDef here as the type might have // 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. // 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) { if (module && _PyModule_GetDef(module) == &_asynciomodule) {
state = get_asyncio_state(module); state = get_asyncio_state(module);
} }
@ -1597,7 +1599,9 @@ FutureIter_dealloc(futureiterobject *it)
it->future = (FutureObj*) state->fi_freelist; it->future = (FutureObj*) state->fi_freelist;
state->fi_freelist = it; state->fi_freelist = it;
} }
else { else
#endif
{
PyObject_GC_Del(it); PyObject_GC_Del(it);
Py_DECREF(tp); Py_DECREF(tp);
} }
@ -1801,6 +1805,7 @@ future_new_iter(PyObject *fut)
asyncio_state *state = get_asyncio_state_by_def((PyObject *)fut); asyncio_state *state = get_asyncio_state_by_def((PyObject *)fut);
ENSURE_FUTURE_ALIVE(state, fut) ENSURE_FUTURE_ALIVE(state, fut)
#ifndef Py_GIL_DISABLED
if (state->fi_freelist_len) { if (state->fi_freelist_len) {
state->fi_freelist_len--; state->fi_freelist_len--;
it = state->fi_freelist; it = state->fi_freelist;
@ -1808,7 +1813,9 @@ future_new_iter(PyObject *fut)
it->future = NULL; it->future = NULL;
_Py_NewReference((PyObject*) it); _Py_NewReference((PyObject*) it);
} }
else { else
#endif
{
it = PyObject_GC_New(futureiterobject, state->FutureIterType); it = PyObject_GC_New(futureiterobject, state->FutureIterType);
if (it == NULL) { if (it == NULL) {
return NULL; return NULL;
@ -3679,6 +3686,7 @@ _asyncio_all_tasks_impl(PyObject *module, PyObject *loop)
static void static void
module_free_freelists(asyncio_state *state) module_free_freelists(asyncio_state *state)
{ {
#ifndef Py_GIL_DISABLED
PyObject *next; PyObject *next;
PyObject *current; PyObject *current;
@ -3693,6 +3701,7 @@ module_free_freelists(asyncio_state *state)
} }
assert(state->fi_freelist_len == 0); assert(state->fi_freelist_len == 0);
state->fi_freelist = NULL; state->fi_freelist = NULL;
#endif
} }
static int static int
@ -3723,6 +3732,7 @@ module_traverse(PyObject *mod, visitproc visit, void *arg)
Py_VISIT(state->context_kwname); Py_VISIT(state->context_kwname);
#ifndef Py_GIL_DISABLED
// Visit freelist. // Visit freelist.
PyObject *next = (PyObject*) state->fi_freelist; PyObject *next = (PyObject*) state->fi_freelist;
while (next != NULL) { while (next != NULL) {
@ -3730,6 +3740,8 @@ module_traverse(PyObject *mod, visitproc visit, void *arg)
Py_VISIT(current); Py_VISIT(current);
next = (PyObject*) ((futureiterobject*) current)->future; next = (PyObject*) ((futureiterobject*) current)->future;
} }
#endif
return 0; return 0;
} }