diff options
author | Sam Gross <colesbury@gmail.com> | 2024-02-20 18:04:37 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-02-20 18:04:37 (GMT) |
commit | e3ad6ca56f9b49db0694f432a870f907a8039f79 (patch) | |
tree | e04a42ed027f6595dec9efe051104d487cfb03a8 /Python | |
parent | d207c7cd5a8c0d3e5f6c5eb947243e4afcd718b0 (diff) | |
download | cpython-e3ad6ca56f9b49db0694f432a870f907a8039f79.zip cpython-e3ad6ca56f9b49db0694f432a870f907a8039f79.tar.gz cpython-e3ad6ca56f9b49db0694f432a870f907a8039f79.tar.bz2 |
gh-115103: Implement delayed free mechanism for free-threaded builds (#115367)
This adds `_PyMem_FreeDelayed()` and supporting functions. The
`_PyMem_FreeDelayed()` function frees memory with the same allocator as
`PyMem_Free()`, but after some delay to ensure that concurrent lock-free
readers have finished.
Diffstat (limited to 'Python')
-rw-r--r-- | Python/pylifecycle.c | 3 | ||||
-rw-r--r-- | Python/pystate.c | 6 |
2 files changed, 9 insertions, 0 deletions
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 656d821..0448734 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1837,6 +1837,9 @@ finalize_interp_clear(PyThreadState *tstate) finalize_interp_types(tstate->interp); + /* Free any delayed free requests immediately */ + _PyMem_FiniDelayed(tstate->interp); + /* finalize_interp_types may allocate Python objects so we may need to abandon mimalloc segments again */ _PyThreadState_ClearMimallocHeaps(tstate); diff --git a/Python/pystate.c b/Python/pystate.c index 1d8c096..bb8e24c 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -617,6 +617,7 @@ init_interpreter(PyInterpreterState *interp, #ifdef Py_GIL_DISABLED _Py_brc_init_state(interp); #endif + llist_init(&interp->mem_free_queue.head); for (int i = 0; i < _PY_MONITORING_UNGROUPED_EVENTS; i++) { interp->monitors.tools[i] = 0; } @@ -1353,6 +1354,7 @@ init_threadstate(_PyThreadStateImpl *_tstate, // Initialize biased reference counting inter-thread queue _Py_brc_init_thread(tstate); #endif + llist_init(&_tstate->mem_free_queue); if (interp->stoptheworld.requested || _PyRuntime.stoptheworld.requested) { // Start in the suspended state if there is an ongoing stop-the-world. @@ -1574,6 +1576,7 @@ PyThreadState_Clear(PyThreadState *tstate) // don't call _PyInterpreterState_SetNotRunningMain() yet. tstate->on_delete(tstate->on_delete_data); } + #ifdef Py_GIL_DISABLED // Each thread should clear own freelists in free-threading builds. struct _Py_object_freelists *freelists = _Py_object_freelists_GET(); @@ -1583,6 +1586,9 @@ PyThreadState_Clear(PyThreadState *tstate) _Py_brc_remove_thread(tstate); #endif + // Merge our queue of pointers to be freed into the interpreter queue. + _PyMem_AbandonDelayed(tstate); + _PyThreadState_ClearMimallocHeaps(tstate); tstate->_status.cleared = 1; |