#include "Python.h"
#include "pycore_dict.h" // _PyDict_GetItem_KnownHash()
+#include "pycore_freelist.h" // _Py_FREELIST_POP()
#include "pycore_modsupport.h" // _PyArg_CheckPositional()
#include "pycore_moduleobject.h" // _PyModule_GetState()
#include "pycore_object.h" // _Py_SetImmortalUntracked
#define Future_Check(state, obj) PyObject_TypeCheck(obj, state->FutureType)
#define Task_Check(state, obj) PyObject_TypeCheck(obj, state->TaskType)
-#define FI_FREELIST_MAXLEN 255
-
#ifdef Py_GIL_DISABLED
# define ASYNCIO_STATE_LOCK(state) PyMutex_Lock(&state->mutex)
# define ASYNCIO_STATE_UNLOCK(state) PyMutex_Unlock(&state->mutex)
/* Counter for autogenerated Task names */
uint64_t task_name_counter;
-#ifndef Py_GIL_DISABLED
- futureiterobject *fi_freelist;
- Py_ssize_t fi_freelist_len;
-#endif
-
/* 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.
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);
- }
-
- // 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;
- }
- else
-#endif
- {
+ if (!_Py_FREELIST_PUSH(futureiters, it, Py_futureiters_MAXFREELIST)) {
PyObject_GC_Del(it);
Py_DECREF(tp);
}
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
-#endif
- {
+ it = _Py_FREELIST_POP(futureiterobject, futureiters);
+ if (it == NULL) {
it = PyObject_GC_New(futureiterobject, state->FutureIterType);
if (it == NULL) {
return NULL;
return tasks;
}
-static void
-module_free_freelists(asyncio_state *state)
-{
-#ifndef Py_GIL_DISABLED
- 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;
-#endif
-}
-
static int
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;
}
Py_CLEAR(state->context_kwname);
- module_free_freelists(state);
-
return 0;
}
free_object(void *obj)
{
PyObject *op = (PyObject *)obj;
- Py_TYPE(op)->tp_free(op);
+ PyTypeObject *tp = Py_TYPE(op);
+ tp->tp_free(op);
+ Py_DECREF(tp);
}
#endif
clear_freelist(&freelists->contexts, is_finalization, free_object);
clear_freelist(&freelists->async_gens, is_finalization, free_object);
clear_freelist(&freelists->async_gen_asends, is_finalization, free_object);
+ clear_freelist(&freelists->futureiters, is_finalization, free_object);
if (is_finalization) {
// Only clear object stack chunks during finalization. We use object
// stacks during GC, so emptying the free-list is counterproductive.