8000 gh-120974: Use common freelist code in asyncio (#122132) · nohlson/cpython@72ead6a · GitHub
[go: up one dir, main page]

Skip to content

Commit 72ead6a

Browse files
colesburynohlson
authored andcommitted
pythongh-120974: Use common freelist code in asyncio (python#122132)
This refactors asyncio to use the common freelist helper functions and macros. As a side effect, the freelist for _asyncio.Future is now re-enabled in the free-threaded build.
1 parent 3e080b1 commit 72ead6a

File tree

3 files changed

+10
-70
lines changed
  • Include/internal
    • < 8000 div class="PRIVATE_VisuallyHidden prc-TreeView-TreeViewVisuallyHidden-4-mPv" aria-hidden="true" id=":R2rdddabH1:">
      pycore_freelist_state.h
  • Modules
  • Objects
  • 3 files changed

    +10
    -70
    lines changed

    Include/internal/pycore_freelist_state.h

    Lines changed: 2 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -20,6 +20,7 @@ extern "C" {
    2020
    # define Py_contexts_MAXFREELIST 255
    2121
    # define Py_async_gens_MAXFREELIST 80
    2222
    # define Py_async_gen_asends_MAXFREELIST 80
    23+
    # define Py_futureiters_MAXFREELIST 255
    2324
    # define Py_object_stack_chunks_MAXFREELIST 4
    2425
    #else
    2526
    # define PyTuple_MAXSAVESIZE 0
    @@ -47,6 +48,7 @@ struct _Py_freelists {
    4748
    struct _Py_freelist contexts;
    4849
    struct _Py_freelist async_gens;
    4950
    struct _Py_freelist async_gen_asends;
    51+
    struct _Py_freelist futureiters;
    5052
    struct _Py_freelist object_stack_chunks;
    5153
    #else
    5254
    char _unused; // Empty structs are not allowed.

    Modules/_asynciomodule.c

    Lines changed: 4 additions & 69 deletions
    Original file line numberDiff line numberDiff line change
    @@ -4,6 +4,7 @@
    44

    55
    #include "Python.h"
    66
    #include "pycore_dict.h" // _PyDict_GetItem_KnownHash()
    7+
    #include "pycore_freelist.h" // _Py_FREELIST_POP()
    78
    #include "pycore_modsupport.h" // _PyArg_CheckPositional()
    89
    #include "pycore_moduleobject.h" // _PyModule_GetState()
    910
    #include "pycore_object.h" // _Py_SetImmortalUntracked
    @@ -75,8 +76,6 @@ typedef struct {
    7576
    #define Future_Check(state, obj) PyObject_TypeCheck(obj, state->FutureType)
    7677
    #define Task_Check(state, obj) PyObject_TypeCheck(obj, state->TaskType)
    7778

    78-
    #define FI_FREELIST_MAXLEN 255
    79-
    8079
    #ifdef Py_GIL_DISABLED
    8180
    # define ASYNCIO_STATE_LOCK(state) PyMutex_Lock(&state->mutex)
    8281
    # define ASYNCIO_STATE_UNLOCK(state) PyMutex_Unlock(&state->mutex)
    @@ -138,11 +137,6 @@ typedef struct {
    138137
    /* Counter for autogenerated Task names */
    139138
    uint64_t task_name_counter;
    140139

    141-
    #ifndef Py_GIL_DISABLED
    142-
    futureiterobject *fi_freelist;
    143-
    Py_ssize_t fi_freelist_len;
    144-
    #endif
    145-
    146140
    /* Linked-list of all tasks which are instances of asyncio.Task or subclasses
    147141
    of it. Third party tasks implementations which don't inherit from
    148142
    asyncio.Task are tracked separately using the 'non_asyncio_tasks' WeakSet.
    @@ -1584,24 +1578,7 @@ FutureIter_dealloc(futureiterobject *it)
    15841578
    PyObject_GC_UnTrack(it);
    15851579
    tp->tp_clear((PyObject *)it);
    15861580

    1587-
    #ifndef Py_GIL_DISABLED
    1588-
    // GH-115874: We can't use PyType_GetModuleByDef here as the type might have
    1589-
    // already been cleared, which is also why we must check if ht_module != NULL.
    1590-
    PyObject *module = ((PyHeapTypeObject*)tp)->ht_module;
    1591-
    asyncio_state *state = NULL;
    1592-
    if (module && _PyModule_GetDef(module) == &_asynciomodule) {
    1593-
    state = get_asyncio_state(module);
    1594-
    }
    1595-
    1596-
    // TODO GH-121621: This should be moved to thread state as well.
    1597-
    if (state && state->fi_freelist_len < FI_FREELIST_MAXLEN) {
    1598-
    state->fi_freelist_len++;
    1599-
    it->future = (FutureObj*) state->fi_freelist;
    1600-
    state->fi_freelist = it;
    1601-
    }
    1602-
    else
    1603-
    #endif
    1604-
    {
    1581+
    if (!_Py_FREELIST_PUSH(futureiters, it, Py_futureiters_MAXFREELIST)) {
    16051582
    PyObject_GC_Del(it);
    16061583
    Py_DECREF(tp);
    16071584
    }
    @@ -1805,17 +1782,8 @@ future_new_iter(PyObject *fut)
    18051782
    asyncio_state *state = get_asyncio_state_by_def((PyObject *)fut);
    18061783
    ENSURE_FUTURE_ALIVE(state, fut)
    18071784

    1808-
    #ifndef Py_GIL_DISABLED
    1809-
    if (state->fi_freelist_len) {
    1810-
    state->fi_freelist_len--;
    1811-
    it = state->fi_freelist;
    1812-
    state->fi_freelist = (futureiterobject*) it->future;
    1813-
    it->future = NULL;
    1814-
    _Py_NewReference((PyObject*) it);
    1815-
    }
    1816-
    else
    1817-
    #endif
    1818-
    {
    1785+
    it = _Py_FREELIST_POP(futureiterobject, futureiters);
    1786+
    if (it == NULL) {
    18191787
    it = PyObject_GC_New(futureiterobject, state->FutureIterType);
    18201788
    if (it == NULL) {
    18211789
    return NULL;
    @@ -3678,27 +3646,6 @@ _asyncio_all_tasks_impl(PyObject *module, PyObject *loop)
    36783646
    return tasks;
    36793647
    }
    36803648

    3681-
    static void
    3682-
    module_free_freelists(asyncio_state *state)
    3683-
    {
    3684-
    #ifndef Py_GIL_DISABLED
    3685-
    PyObject *next;
    3686-
    PyObject *current;
    3687-
    3688-
    next = (PyObject*) state->fi_freelist;
    3689-
    while (next != NULL) {
    3690-
    assert(state->fi_freelist_len > 0);
    3691-
    state->fi_freelist_len--;
    3692-
    3693-
    current = next;
    3694-
    next = (PyObject*) ((futureiterobject*) current)->future;
    3695-
    PyObject_GC_Del(current);
    3696-
    }
    3697-
    assert(state->fi_freelist_len == 0);
    3698-
    state->fi_freelist = NULL;
    3699-
    #endif
    3700-
    }
    3701-
    37023649
    static int
    37033650
    module_traverse(PyObject *mod, visitproc visit, void *arg)
    37043651
    {
    @@ -3727,16 +3674,6 @@ module_traverse(PyObject *mod, visitproc visit, void *arg)
    37273674

    37283675
    Py_VISIT(state->context_kwname);
    37293676

    3730-
    #ifndef Py_GIL_DISABLED
    3731-
    // Visit freelist.
    3732-
    PyObject *next = (PyObject*) state->fi_freelist;
    3733-
    while (next != NULL) {
    3734-
    PyObject *current = next;
    3735-
    Py_VISIT(current);
    3736-
    next = (PyObject*) ((futureiterobject*) current)->future;
    3737-
    }
    3738-
    #endif
    3739-
    37403677
    return 0;
    37413678
    }
    37423679

    @@ -3768,8 +3705,6 @@ module_clear(PyObject *mod)
    37683705

    37693706
    Py_CLEAR(state->context_kwname);
    37703707

    3771-
    module_free_freelists(state);
    3772-
    37733708
    return 0;
    37743709
    }
    37753710

    Objects/object.c

    Lines changed: 4 additions & 1 deletion
    Original file line numberDiff line numberDiff line change
    @@ -829,7 +829,9 @@ static void
    829829
    free_object(void *obj)
    830830
    {
    831831
    PyObject *op = (PyObject *)obj;
    832-
    Py_TYPE(op)->tp_free(op);
    832+
    PyTypeObject *tp = Py_TYPE(op);
    833+
    tp->tp_free(op);
    834+
    Py_DECREF(tp);
    833835
    }
    834836

    835837
    #endif
    @@ -851,6 +853,7 @@ _PyObject_ClearFreeLists(struct _Py_freelists *freelists, int is_finalization)
    851853
    clear_freelist(&freelists->contexts, is_finalization, free_object);
    852854
    clear_freelist(&freelists->async_gens, is_finalization, free_object);
    853855
    clear_freelist(&freelists->async_gen_asends, is_finalization, free_object);
    856+
    clear_freelist(&freelists->futureiters, is_finalization, free_object);
    854857
    if (is_finalization) {
    855858
    // Only clear object stack chunks during finalization. We use object
    856859
    // stacks during GC, so emptying the free-list is counterproductive.

    0 commit comments

    Comments
     (0)
    0