mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			152 lines
		
	
	
	
		
			4.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			152 lines
		
	
	
	
		
			4.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #ifndef Py_INTERNAL_PYMEM_H
 | |
| #define Py_INTERNAL_PYMEM_H
 | |
| 
 | |
| #include "pycore_llist.h"           // struct llist_node
 | |
| #include "pycore_lock.h"            // PyMutex
 | |
| 
 | |
| #ifdef __cplusplus
 | |
| extern "C" {
 | |
| #endif
 | |
| 
 | |
| #ifndef Py_BUILD_CORE
 | |
| #  error "this header requires Py_BUILD_CORE define"
 | |
| #endif
 | |
| 
 | |
| // Try to get the allocators name set by _PyMem_SetupAllocators().
 | |
| // Return NULL if unknown.
 | |
| // Export for '_testinternalcapi' shared extension.
 | |
| PyAPI_FUNC(const char*) _PyMem_GetCurrentAllocatorName(void);
 | |
| 
 | |
| // strdup() using PyMem_RawMalloc()
 | |
| extern char* _PyMem_RawStrdup(const char *str);
 | |
| 
 | |
| // strdup() using PyMem_Malloc().
 | |
| // Export for '_pickle ' shared extension.
 | |
| PyAPI_FUNC(char*) _PyMem_Strdup(const char *str);
 | |
| 
 | |
| // wcsdup() using PyMem_RawMalloc()
 | |
| extern wchar_t* _PyMem_RawWcsdup(const wchar_t *str);
 | |
| 
 | |
| typedef struct {
 | |
|     /* We tag each block with an API ID in order to tag API violations */
 | |
|     char api_id;
 | |
|     PyMemAllocatorEx alloc;
 | |
| } debug_alloc_api_t;
 | |
| 
 | |
| struct _pymem_allocators {
 | |
|     PyMutex mutex;
 | |
|     struct {
 | |
|         PyMemAllocatorEx raw;
 | |
|         PyMemAllocatorEx mem;
 | |
|         PyMemAllocatorEx obj;
 | |
|     } standard;
 | |
|     struct {
 | |
|         debug_alloc_api_t raw;
 | |
|         debug_alloc_api_t mem;
 | |
|         debug_alloc_api_t obj;
 | |
|     } debug;
 | |
|     int is_debug_enabled;
 | |
|     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.
 | |
|    Return on success, or return -1 if the domain is unknown. */
 | |
| extern int _PyMem_SetDefaultAllocator(
 | |
|     PyMemAllocatorDomain domain,
 | |
|     PyMemAllocatorEx *old_alloc);
 | |
| 
 | |
| /* Special bytes broadcast into debug memory blocks at appropriate times.
 | |
|    Strings of these are unlikely to be valid addresses, floats, ints or
 | |
|    7-bit ASCII.
 | |
| 
 | |
|    - PYMEM_CLEANBYTE: clean (newly allocated) memory
 | |
|    - PYMEM_DEADBYTE dead (newly freed) memory
 | |
|    - PYMEM_FORBIDDENBYTE: untouchable bytes at each end of a block
 | |
| 
 | |
|    Byte patterns 0xCB, 0xDB and 0xFB have been replaced with 0xCD, 0xDD and
 | |
|    0xFD to use the same values as Windows CRT debug malloc() and free().
 | |
|    If modified, _PyMem_IsPtrFreed() should be updated as well. */
 | |
| #define PYMEM_CLEANBYTE      0xCD
 | |
| #define PYMEM_DEADBYTE       0xDD
 | |
| #define PYMEM_FORBIDDENBYTE  0xFD
 | |
| 
 | |
| /* Heuristic checking if a pointer value is newly allocated
 | |
|    (uninitialized), newly freed or NULL (is equal to zero).
 | |
| 
 | |
|    The pointer is not dereferenced, only the pointer value is checked.
 | |
| 
 | |
|    The heuristic relies on the debug hooks on Python memory allocators which
 | |
|    fills newly allocated memory with CLEANBYTE (0xCD) and newly freed memory
 | |
|    with DEADBYTE (0xDD). Detect also "untouchable bytes" marked
 | |
|    with FORBIDDENBYTE (0xFD). */
 | |
| static inline int _PyMem_IsPtrFreed(const void *ptr)
 | |
| {
 | |
|     uintptr_t value = (uintptr_t)ptr;
 | |
| #if SIZEOF_VOID_P == 8
 | |
|     return (value == 0
 | |
|             || value == (uintptr_t)0xCDCDCDCDCDCDCDCD
 | |
|             || value == (uintptr_t)0xDDDDDDDDDDDDDDDD
 | |
|             || value == (uintptr_t)0xFDFDFDFDFDFDFDFD);
 | |
| #elif SIZEOF_VOID_P == 4
 | |
|     return (value == 0
 | |
|             || value == (uintptr_t)0xCDCDCDCD
 | |
|             || value == (uintptr_t)0xDDDDDDDD
 | |
|             || value == (uintptr_t)0xFDFDFDFD);
 | |
| #else
 | |
| #  error "unknown pointer size"
 | |
| #endif
 | |
| }
 | |
| 
 | |
| extern int _PyMem_GetAllocatorName(
 | |
|     const char *name,
 | |
|     PyMemAllocatorName *allocator);
 | |
| 
 | |
| /* Configure the Python memory allocators.
 | |
|    Pass PYMEM_ALLOCATOR_DEFAULT to use default allocators.
 | |
|    PYMEM_ALLOCATOR_NOT_SET does nothing. */
 | |
| 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);
 | |
| 
 | |
| // Enqueue an object to be freed possibly after some delay
 | |
| #ifdef Py_GIL_DISABLED
 | |
| extern void _PyObject_XDecRefDelayed(PyObject *obj);
 | |
| #else
 | |
| static inline void _PyObject_XDecRefDelayed(PyObject *obj)
 | |
| {
 | |
|     Py_XDECREF(obj);
 | |
| }
 | |
| #endif
 | |
| 
 | |
| // Periodically process delayed free requests.
 | |
| extern void _PyMem_ProcessDelayed(PyThreadState *tstate);
 | |
| 
 | |
| 
 | |
| // Periodically process delayed free requests when the world is stopped.
 | |
| // Notify of any objects whic should be freeed.
 | |
| typedef void (*delayed_dealloc_cb)(PyObject *, void *);
 | |
| extern void _PyMem_ProcessDelayedNoDealloc(PyThreadState *tstate,
 | |
|                                            delayed_dealloc_cb cb, void *state);
 | |
| 
 | |
| // 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
 | |
| #endif  // !Py_INTERNAL_PYMEM_H
 | 
