gh-121621: Move asyncio freelist to thread state by Fidget-Spinner · Pull Request #121915 · python/cpython
futureiterobject *fi_freelist; Py_ssize_t fi_freelist_len;
/* Linked-list of all tasks which are instances of asyncio.Task or subclasses of it. Third party tasks implementations which don't inherit from asyncio.Task are tracked separately using the 'non_asyncio_tasks' WeakSet.
#ifdef WITH_FREELISTS static struct _Py_asyncmodule_futureiter_freelist * get_futureiter_freelist(void) { struct _Py_object_freelists *freelists = _Py_object_freelists_GET(); assert(freelists != NULL); return &freelists->futureiters; } #endif
/*[clinic input] class _asyncio.Future "FutureObj *" "&Future_Type" [clinic start generated code]*/
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);
// 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. if (module && _PyModule_GetDef(module) == &_asynciomodule) { state = get_asyncio_state(module); }
// TODO GH-121621: This should be moved to thread state as well. if (state && state->fi_freelist_len < FI_FREELIST_MAXLEN) { state->fi_freelist_len++; it->future = (FutureObj*) state->fi_freelist; state->fi_freelist = it; #ifdef WITH_FREELISTS struct _Py_asyncmodule_futureiter_freelist* freelist = get_futureiter_freelist(); if (freelist->fi_freelist_len < FI_FREELIST_MAXLEN) { freelist->fi_freelist_len++; it->future = (FutureObj*) freelist->fi_freelist; freelist->fi_freelist = it; } else { else #endif { PyObject_GC_Del(it); Py_DECREF(tp); }
if (state->fi_freelist_len) { state->fi_freelist_len--; it = state->fi_freelist; state->fi_freelist = (futureiterobject*) it->future; #ifdef WITH_FREELISTS struct _Py_asyncmodule_futureiter_freelist* freelist = get_futureiter_freelist(); if (freelist->fi_freelist_len) { freelist->fi_freelist_len--; it = freelist->fi_freelist; freelist->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;
/*[clinic input] _asyncio._clear_freelist
Clears the asyncio freelist.
Internal CPython implementation detail. Do not depend on this or use it! This function is thread-specific.
[clinic start generated code]*/
static PyObject * _asyncio__clear_freelist_impl(PyObject *module) /*[clinic end generated code: output=8d0e295bbbe2f8b6 input=f3ef7630d66cf63a]*/ { _PyAsyncModule_ClearFreeLists(_Py_object_freelists_GET(), 0); Py_RETURN_NONE; }
/*[clinic input] _asyncio._get_running_loop
static void module_free_freelists(asyncio_state *state) { PyObject *next; PyObject *current;
next = (PyObject*) state->fi_freelist; while (next != NULL) { assert(state->fi_freelist_len > 0); state->fi_freelist_len--;
current = next; next = (PyObject*) ((futureiterobject*) current)->future; PyObject_GC_Del(current); } assert(state->fi_freelist_len == 0); state->fi_freelist = NULL; }
static int module_traverse(PyObject *mod, visitproc visit, void *arg)
Py_VISIT(state->context_kwname);
// Visit freelist. PyObject *next = (PyObject*) state->fi_freelist; while (next != NULL) { PyObject *current = next; Py_VISIT(current); next = (PyObject*) ((futureiterobject*) current)->future; } return 0; }
Py_CLEAR(state->context_kwname);
module_free_freelists(state); _PyAsyncModule_ClearFreeLists(_Py_object_freelists_GET(), 0);
return 0; }