summaryrefslogtreecommitdiffstats
path: root/Include
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 /Include
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 'Include')
-rw-r--r--Include/internal/pycore_interp.h1
-rw-r--r--Include/internal/pycore_pymem.h19
-rw-r--r--Include/internal/pycore_pymem_init.h5
-rw-r--r--Include/internal/pycore_runtime_init.h1
-rw-r--r--Include/internal/pycore_tstate.h1
5 files changed, 27 insertions, 0 deletions
diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h
index 06eba66..6a00aaf 100644
--- a/Include/internal/pycore_interp.h
+++ b/Include/internal/pycore_interp.h
@@ -231,6 +231,7 @@ struct _is {
struct _Py_dict_state dict_state;
struct _Py_exc_state exc_state;
+ struct _Py_mem_interp_free_queue mem_free_queue;
struct ast_state ast;
struct types_state types;
diff --git a/Include/internal/pycore_pymem.h b/Include/internal/pycore_pymem.h
index 1a72d07..1aea91a 100644
--- a/Include/internal/pycore_pymem.h
+++ b/Include/internal/pycore_pymem.h
@@ -1,6 +1,7 @@
#ifndef Py_INTERNAL_PYMEM_H
#define Py_INTERNAL_PYMEM_H
+#include "pycore_llist.h" // struct llist_node
#include "pycore_lock.h" // PyMutex
#ifdef __cplusplus
@@ -48,6 +49,11 @@ struct _pymem_allocators {
PyObjectArenaAllocator obj_arena;
};
+struct _Py_mem_interp_free_queue {
+ int has_work; // true if the queue is not empty
+ PyMutex mutex; // protects the queue
+ struct llist_node head; // queue of _mem_work_chunk items
+};
/* Set the memory allocator of the specified domain to the default.
Save the old allocator into *old_alloc if it's non-NULL.
@@ -110,6 +116,19 @@ extern int _PyMem_SetupAllocators(PyMemAllocatorName allocator);
/* Is the debug allocator enabled? */
extern int _PyMem_DebugEnabled(void);
+// Enqueue a pointer to be freed possibly after some delay.
+extern void _PyMem_FreeDelayed(void *ptr);
+
+// Periodically process delayed free requests.
+extern void _PyMem_ProcessDelayed(PyThreadState *tstate);
+
+// Abandon all thread-local delayed free requests and push them to the
+// interpreter's queue.
+extern void _PyMem_AbandonDelayed(PyThreadState *tstate);
+
+// On interpreter shutdown, frees all delayed free requests.
+extern void _PyMem_FiniDelayed(PyInterpreterState *interp);
+
#ifdef __cplusplus
}
#endif
diff --git a/Include/internal/pycore_pymem_init.h b/Include/internal/pycore_pymem_init.h
index 96c49ed..c593edc 100644
--- a/Include/internal/pycore_pymem_init.h
+++ b/Include/internal/pycore_pymem_init.h
@@ -92,6 +92,11 @@ extern void _PyMem_ArenaFree(void *, void *, size_t);
{ NULL, _PyMem_ArenaAlloc, _PyMem_ArenaFree }
+#define _Py_mem_free_queue_INIT(queue) \
+ { \
+ .head = LLIST_INIT(queue.head), \
+ }
+
#ifdef __cplusplus
}
#endif
diff --git a/Include/internal/pycore_runtime_init.h b/Include/internal/pycore_runtime_init.h
index be81604..d093047 100644
--- a/Include/internal/pycore_runtime_init.h
+++ b/Include/internal/pycore_runtime_init.h
@@ -176,6 +176,7 @@ extern PyTypeObject _PyExc_MemoryError;
}, \
.dtoa = _dtoa_state_INIT(&(INTERP)), \
.dict_state = _dict_state_INIT, \
+ .mem_free_queue = _Py_mem_free_queue_INIT(INTERP.mem_free_queue), \
.func_state = { \
.next_version = 1, \
}, \
diff --git a/Include/internal/pycore_tstate.h b/Include/internal/pycore_tstate.h
index d0f980e..e268e6f 100644
--- a/Include/internal/pycore_tstate.h
+++ b/Include/internal/pycore_tstate.h
@@ -29,6 +29,7 @@ typedef struct _PyThreadStateImpl {
PyThreadState base;
struct _qsbr_thread_state *qsbr; // only used by free-threaded build
+ struct llist_node mem_free_queue; // delayed free queue
#ifdef Py_GIL_DISABLED
struct _gc_thread_state gc;