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.
This commit is contained in:
Sam Gross 2024-02-20 13:04:37 -05:00 committed by GitHub
parent d207c7cd5a
commit e3ad6ca56f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 226 additions and 0 deletions

View file

@ -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