summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
authorSam Gross <colesbury@gmail.com>2024-02-20 18:04:37 (GMT)
committerGitHub <noreply@github.com>2024-02-20 18:04:37 (GMT)
commite3ad6ca56f9b49db0694f432a870f907a8039f79 (patch)
treee04a42ed027f6595dec9efe051104d487cfb03a8 /Python
parentd207c7cd5a8c0d3e5f6c5eb947243e4afcd718b0 (diff)
downloadcpython-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.c3
-rw-r--r--Python/pystate.c6
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;