/* ------------------------------------------------------------------------- * * palloc.h * openGauss memory allocator definitions. * * This file contains the basic memory allocation interface that is * needed by almost every backend module. It is included directly by * postgres.h, so the definitions here are automatically available * everywhere. Keep it lean! * * Memory allocation occurs within "contexts". Every chunk obtained from * palloc()/MemoryContextAlloc() is allocated within a specific context. * The entire contents of a context can be freed easily and quickly by * resetting or deleting the context --- this is both faster and less * prone to memory-leakage bugs than releasing chunks individually. * We organize contexts into context trees to allow fine-grain control * over chunk lifetime while preserving the certainty that we will free * everything that should be freed. See utils/mmgr/README for more info. * * * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * src/include/utils/palloc.h * * ------------------------------------------------------------------------- */ #ifndef PALLOC_H #define PALLOC_H #ifndef FRONTEND_PARSER #include #include #include "postgres.h" #include "c.h" #include "nodes/nodes.h" #include "nodes/pg_list.h" typedef struct MemoryContextData* MemoryContext; /* * MemoryContext * A logical context in which memory allocations occur. * * MemoryContext itself is an abstract type that can have multiple * implementations, though for now we have only AllocSetContext. * The function pointers in MemoryContextMethods define one specific * implementation of MemoryContext --- they are a virtual function table * in C++ terms. * * Node types that are actual implementations of memory contexts must * begin with the same fields as MemoryContext. * * Note: for largely historical reasons, typedef MemoryContext is a pointer * to the context struct rather than the struct type itself. */ typedef struct MemoryContextMethods { void* (*alloc)(MemoryContext context, Size align, Size size, const char* file, int line); /* call this free_p in case someone #define's free() */ void (*free_p)(MemoryContext context, void* pointer); void* (*realloc)(MemoryContext context, void* pointer, Size align, Size size, const char* file, int line); void (*init)(MemoryContext context); void (*reset)(MemoryContext context); void (*delete_context)(MemoryContext context); Size (*get_chunk_space)(MemoryContext context, void* pointer); bool (*is_empty)(MemoryContext context); void (*stats)(MemoryContext context, int level); #ifdef MEMORY_CONTEXT_CHECKING void (*check)(MemoryContext context); #endif } MemoryContextMethods; /* * McxtAllocationMethods * A virtual function table for memory allocation from memory context. */ typedef struct McxtAllocationMethods { void *(*alloc_from_context)(MemoryContext context, Size size, const char* file, int line); void *(*alloc_from_context_debug)(MemoryContext context, Size size, const char* file, int line); void *(*alloc_zero_from_context_debug)(MemoryContext context, Size size, const char* file, int line); void *(*alloc_zero_aligned_from_context_debug)(MemoryContext context, Size size, const char* file, int line); void *(*alloc_huge_from_context_debug)(MemoryContext context, Size size, const char* file, int line); void *(*alloc_huge_zero_from_context_debug)(MemoryContext context, Size size, const char* file, int line); void* (*alloc_extend_from_context_debug)(MemoryContext context, Size size, int flags, const char* file, int line); char *(*strdup_from_context_debug)(MemoryContext context, const char* string, const char* file, int line); void *(*alloc_extend)(Size size, int flags); void *(*alloc_noexcept)(Size size); } McxtAllocationMethods; /* * McxtOperationMethods * A virtual function table for memory-context-type-independent functions. */ typedef struct McxtOperationMethods { void (*mcxt_reset)(MemoryContext context); void (*mcxt_delete)(MemoryContext context); void (*mcxt_delete_children)(MemoryContext context, List* context_list); void (*mcxt_destroy)(MemoryContext context); void (*mcxt_reset_and_delete_children)(MemoryContext context); void (*mcxt_set_parent)(MemoryContext context, MemoryContext new_parent); #ifdef MEMORY_CONTEXT_CHECKING void (*mcxt_check)(MemoryContext context, bool own_by_session); #endif } McxtOperationMethods; /* * A memory context can have callback functions registered on it. Any such * function will be called once just before the context is next reset or * deleted. The MemoryContextCallback struct describing such a callback * typically would be allocated within the context itself, thereby avoiding * any need to manage it explicitly (the reset/delete action will free it). */ typedef void (*MemoryContextCallbackFunction) (std::shared_ptr arg); typedef struct MemoryContextCallback { MemoryContextCallbackFunction func; /* function to call */ std::shared_ptr arg; /* argument to pass it */ struct MemoryContextCallback *next; /* next in list of callbacks */ } MemoryContextCallback; typedef struct MemoryContextData { NodeTag type; /* identifies exact kind of context */ bool is_sealed; /* sealed context prevent any memory change */ bool is_shared; /* context is shared by threads */ bool isReset; /* T = no space alloced since last reset */ bool allowInCritSection; /* allow palloc in critical section */ MemoryContextMethods* methods; /* virtual function table */ McxtAllocationMethods* alloc_methods; McxtOperationMethods* mcxt_methods; MemoryContext parent; /* NULL if no parent (toplevel context) */ MemoryContext firstchild; /* head of linked list of children */ MemoryContext prevchild; /* previous child of same parent */ MemoryContext nextchild; /* next child of same parent */ char* name; /* context name (just for debugging) */ MemoryContextCallback *resetCbs; /* list of reset/delete callbacks */ pthread_rwlock_t lock; /* lock to protect members if the context is shared */ int level; /* context level */ uint64 session_id; /* session id of context owner */ ThreadId thread_id; /* thread id of context owner */ ListCell cell; /* cell to pointer to this context*/ } MemoryContextData; /* * CurrentMemoryContext is the default allocation context for palloc(). * We declare it here so that palloc() can be a macro. Avoid accessing it * directly! Instead, use MemoryContextSwitchTo() to change the setting. */ #ifdef WIN32 extern THR_LOCAL MemoryContext CurrentMemoryContext; extern THR_LOCAL MemoryContext SelfMemoryContext; extern THR_LOCAL MemoryContext TopMemoryContext; #else extern THR_LOCAL PGDLLIMPORT MemoryContext CurrentMemoryContext; extern THR_LOCAL PGDLLIMPORT MemoryContext SelfMemoryContext; extern THR_LOCAL PGDLLIMPORT MemoryContext TopMemoryContext; #endif /* WIN32 */ #ifdef MEMORY_CONTEXT_CHECKING const uint64 BlkMagicNum = 0xDADADADADADADADA; const uint32 PremagicNum = 0xBABABABA; #endif /* * Flags for MemoryContextAllocExtended. */ #define MCXT_ALLOC_HUGE 0x01 /* allow huge allocation (> 1 GB) */ #define MCXT_ALLOC_NO_OOM 0x02 /* no failure if out-of-memory */ #define MCXT_ALLOC_ZERO 0x04 /* zero allocated memory */ #define ENABLE_MEMORY_PROTECT() (t_thrd.utils_cxt.memNeedProtect = true) #define DISABLE_MEMORY_PROTECT() (t_thrd.utils_cxt.memNeedProtect = false) /* Definition for the unchanged interfaces */ #ifndef MEMORY_CONTEXT_CHECKING #define MemoryContextAlloc(context, size) \ (((MemoryContext)context)->alloc_methods->alloc_from_context(context, size, __FILE__, __LINE__)) #else #define MemoryContextAlloc(context, size) \ (((MemoryContext)context)->alloc_methods->alloc_from_context_debug(context, size, __FILE__, __LINE__)) #endif /* MEMORY_CONTEXT_CHECKING */ #define MemoryContextAllocZero(context, size) \ (((MemoryContext)context)->alloc_methods->alloc_zero_from_context_debug(context, size, __FILE__, __LINE__)) #define MemoryContextAllocZeroAligned(context, size) \ (((MemoryContext)context)->alloc_methods->alloc_zero_aligned_from_context_debug(context, size, __FILE__, __LINE__)) #define MemoryContextAllocExtended(context, size, flags) \ (((MemoryContext)context)->alloc_methods->alloc_extend_from_context_debug(context, size, flags, __FILE__, __LINE__)) #define MemoryContextStrdup(context, str) \ (((MemoryContext)context)->alloc_methods->strdup_from_context_debug(context, str, __FILE__, __LINE__)) #define palloc_huge(context, size) \ (((MemoryContext)context)->alloc_methods->alloc_huge_from_context_debug(context, size, __FILE__, __LINE__)) #define palloc0_huge(context, size) \ (((MemoryContext)context)->alloc_methods->alloc_huge_zero_from_context_debug(context, size, __FILE__, __LINE__)) #ifndef FRONTEND #define palloc(sz) \ (MemoryContextAlloc(CurrentMemoryContext, (sz))) #define palloc_extended(size, flags) \ (CurrentMemoryContext->alloc_methods->alloc_extend(size, flags)) #endif #define palloc0_noexcept(size) \ (CurrentMemoryContext->alloc_methods->alloc_noexcept(size)) #define palloc0(sz) MemoryContextAllocZero(CurrentMemoryContext, (sz)) #define selfpalloc(sz) MemoryContextAlloc(SelfMemoryContext, (sz)) #define selfpalloc0(sz) MemoryContextAllocZero(SelfMemoryContext, (sz)) #define selfpstrdup(str) MemoryContextStrdup(SelfMemoryContext, (str)) #define pstrdup(str) MemoryContextStrdup(CurrentMemoryContext, (str)) #define pstrdup_ext(str) \ (((str) == NULL) ? NULL : (pstrdup((const char*)(str)))) /* * The result of palloc() is always word-aligned, so we can skip testing * alignment of the pointer when deciding which MemSet variant to use. * Note that this variant does not offer any advantage, and should not be * used, unless its "sz" argument is a compile-time constant; therefore, the * issue that it evaluates the argument multiple times isn't a problem in * practice. */ #define palloc0fast(sz) \ (MemSetTest(0, sz) ? MemoryContextAllocZeroAligned(CurrentMemoryContext, sz) \ : MemoryContextAllocZero(CurrentMemoryContext, sz)) #define repalloc(pointer, size) \ repallocDebug(pointer, size, __FILE__, __LINE__) #define repalloc_noexcept(pointer, size) \ repalloc_noexcept_Debug(pointer, size, __FILE__, __LINE__) #define pnstrdup(in, len) \ pnstrdupDebug(in, len, __FILE__, __LINE__) #define INSTANCE_GET_MEM_CXT_GROUP g_instance.mcxt_group->GetMemCxtGroup #define THREAD_GET_MEM_CXT_GROUP t_thrd.mcxt_group->GetMemCxtGroup #define SESS_GET_MEM_CXT_GROUP u_sess->mcxt_group->GetMemCxtGroup /* * Fundamental memory-allocation operations (more are in utils/memutils.h) */ extern void* MemoryAllocFromContext(MemoryContext context, Size size, const char* file, int line); extern void* MemoryContextAllocDebug(MemoryContext context, Size size, const char* file, int line); extern void* MemoryContextAllocHugeDebug(MemoryContext context, Size size, const char* file, int line); extern void* MemoryContextAllocHugeZeroDebug(MemoryContext context, Size size, const char* file, int line); extern void* repallocHugeDebug(void* pointer, Size size, const char* file, int line); extern void* MemoryContextAllocZeroDebug(MemoryContext context, Size size, const char* file, int line); extern void* MemoryContextAllocZeroAlignedDebug(MemoryContext context, Size size, const char* file, int line); extern void* MemoryContextAllocExtendedDebug(MemoryContext context, Size size, int flags, const char* file, int line); extern char* MemoryContextStrdupDebug(MemoryContext context, const char* string, const char* file, int line); extern void* MemoryContextMemalignAllocDebug(MemoryContext context, Size align, Size size, const char* file, int line); extern void MemoryContextMemalignFree(MemoryContext context, void* pointer); extern void* std_palloc_extended(Size size, int flags); extern void* std_palloc0_noexcept(Size size); extern void* opt_MemoryAllocFromContext(MemoryContext context, Size size, const char* file, int line); #define opt_MemoryContextAllocDebug(context, size, file, line) \ opt_MemoryAllocFromContext(context, size, file, line) #define opt_MemoryContextAllocHugeDebug(context, size, file, line) \ opt_MemoryAllocFromContext(context, size, file, line) extern void* opt_MemoryContextAllocHugeZeroDebug(MemoryContext context, Size size, const char* file, int line); extern void* opt_MemoryContextAllocZeroDebug(MemoryContext context, Size size, const char* file, int line); extern void* opt_MemoryContextAllocZeroAlignedDebug(MemoryContext context, Size size, const char* file, int line); extern void* opt_MemoryContextAllocExtendedDebug(MemoryContext context, Size size, int flags, const char* file, int line); extern char* opt_MemoryContextStrdupDebug(MemoryContext context, const char* string, const char* file, int line); extern void* opt_palloc_extended(Size size, int flags); extern void* opt_palloc0_noexcept(Size size); #define repalloc_huge(pointer, size) repallocHugeDebug(pointer, size, __FILE__, __LINE__) #define selfrepalloc(ptr, sz) repalloc((ptr), (sz)) extern THR_LOCAL MemoryContext AlignMemoryContext; #define mem_align_alloc(align, size) \ MemoryContextMemalignAllocDebug(AlignMemoryContext, (align), (size), __FILE__, __LINE__) #define mem_align_free(ptr) MemoryContextMemalignFree(AlignMemoryContext, (ptr)) extern void pfree(void* pointer); extern void opt_pfree(void* pointer); #define selfpfree(ptr) pfree((ptr)) template bool isConst(T& x) { return false; } template bool isConst(T const& x) { return true; } #define FREE_POINTER(ptr) \ do { \ if ((ptr) != NULL) { \ pfree((void*)ptr); \ if (!isConst(ptr)) \ (ptr) = NULL; \ } \ } while (0) // call pfree() and set pointer to be NULL. #define pfree_ext(__p) FREE_POINTER(__p) extern void* repallocDebug(void* pointer, Size size, const char* file, int line); extern void* opt_repallocDebug(void* pointer, Size size, const char* file, int line); extern void* repalloc_noexcept_Debug(void* pointer, Size size, const char* file, int line); extern void* opt_repalloc_noexcept_Debug(void* pointer, Size size, const char* file, int line); /* * MemoryContextSwitchTo can't be a macro in standard C compilers. * But we can make it an inline function if the compiler supports it. * * This file has to be includable by some non-backend code such as * pg_resetxlog, so don't expose the CurrentMemoryContext reference * if FRONTEND is defined. */ #if defined(USE_INLINE) && !defined(FRONTEND) static inline MemoryContext MemoryContextSwitchTo(MemoryContext context) { MemoryContext old = CurrentMemoryContext; CurrentMemoryContext = context; return old; } #else extern MemoryContext MemoryContextSwitchTo(MemoryContext context); #endif /* USE_INLINE && !FRONTEND */ /* Registration of memory context reset/delete callbacks */ extern void MemoryContextRegisterResetCallback(MemoryContext context, MemoryContextCallback *cb); /* * These are like standard strdup() except the copied string is * allocated in a context, not with malloc(). */ extern char* MemoryContextStrdupDebug(MemoryContext context, const char* string, const char* file, int line); extern char* pnstrdupDebug(const char* in, Size len, const char* file, int line); extern void AllocSetCheckPointer(void* pointer); #if defined(WIN32) || defined(__CYGWIN__) extern void* pgport_palloc(Size sz); extern char* pgport_pstrdup(const char* str); extern void pgport_pfree(void* pointer); #endif #define New(pmc) new (pmc, __FILE__, __LINE__) // BaseObject is a basic class // All other class should inherit from BaseObject class which // override operator new/delete. // class BaseObject { public: ~BaseObject() {} void* operator new(size_t size, MemoryContextData* pmc, const char* file, int line) { return MemoryContextAllocDebug(pmc, size, file, line); } void* operator new[](size_t size, MemoryContextData* pmc, const char* file, int line) { return MemoryContextAllocDebug(pmc, size, file, line); } void operator delete(void* p) { pfree(p); } void operator delete[](void* p) { pfree(p); } }; typedef struct { std::shared_ptr data; void (*cleanup)(std::shared_ptr data); /* cleanup hook */ } PortalSpecialData; /* *It is used for delete object whose destructor is null and free memory in Destroy() *_objptr can't include type change, for example (A*)b, that will lead to compile error in (_objptr) = NULL *If _objptr include type change, please use DELETE_EX_TYPE to complete it. *It is supplied easily for developers to refactor destructor in the future */ #define DELETE_EX(_objptr) \ do { \ (_objptr)->Destroy(); \ delete (_objptr); \ (_objptr) = NULL; \ } while (0) // used for _objptr need to change to another type #define DELETE_EX_TYPE(_objptr, _type) \ do { \ ((_type*)(_objptr))->Destroy(); \ delete (_type*)(_objptr); \ (_objptr) = NULL; \ } while (0) #define DELETE_EX2(_objptr) \ do { \ if ((_objptr) != nullptr) { \ delete (_objptr); \ (_objptr) = NULL; \ } \ } while (0) #endif /* !FRONTEND_PARSER */ #endif /* PALLOC_H */