*/
#define ALLOC_BLOCKHDRSZ MAXALIGN(sizeof(AllocBlockData))
-#define ALLOC_CHUNKHDRSZ MAXALIGN(sizeof(AllocChunkData))
-
-/* Portion of ALLOC_CHUNKHDRSZ examined outside aset.c. */
-#define ALLOC_CHUNK_PUBLIC \
- (offsetof(AllocChunkData, size) + sizeof(Size))
-
-/* Portion of ALLOC_CHUNKHDRSZ excluding trailing padding. */
-#ifdef MEMORY_CONTEXT_CHECKING
-#define ALLOC_CHUNK_USED \
- (offsetof(AllocChunkData, requested_size) + sizeof(Size))
-#else
-#define ALLOC_CHUNK_USED \
- (offsetof(AllocChunkData, size) + sizeof(Size))
-#endif
+#define ALLOC_CHUNKHDRSZ sizeof(struct AllocChunkData)
typedef struct AllocBlockData *AllocBlock; /* forward reference */
typedef struct AllocChunkData *AllocChunk;
/*
* AllocChunk
* The prefix of each piece of memory in an AllocBlock
- *
- * NB: this MUST match StandardChunkHeader as defined by utils/memutils.h.
*/
typedef struct AllocChunkData
{
- /* aset is the owning aset if allocated, or the freelist link if free */
- void *aset;
/* size is always the size of the usable space in the chunk */
Size size;
#ifdef MEMORY_CONTEXT_CHECKING
/* when debugging memory usage, also store actual requested size */
/* this is zero in a free chunk */
Size requested_size;
+#if MAXIMUM_ALIGNOF > 4 && SIZEOF_VOID_P == 4
+ Size padding;
#endif
+
+#endif /* MEMORY_CONTEXT_CHECKING */
+
+ /* aset is the owning aset if allocated, or the freelist link if free */
+ void *aset;
+
+ /* there must not be any padding to reach a MAXALIGN boundary here! */
} AllocChunkData;
/*
{
AllocSet set;
+ StaticAssertStmt(offsetof(AllocChunkData, aset) + sizeof(MemoryContext) ==
+ MAXALIGN(sizeof(AllocChunkData)),
+ "padding calculation in AllocChunkData is wrong");
+
/*
* First, validate allocation parameters. (If we're going to throw an
* error, we should do so before the context is created, not after.) We
AllocAllocInfo(set, chunk);
/*
- * Chunk header public fields remain DEFINED. The requested
- * allocation itself can be NOACCESS or UNDEFINED; our caller will
- * soon make it UNDEFINED. Make extra space at the end of the chunk,
- * if any, NOACCESS.
+ * Chunk's metadata fields remain DEFINED. The requested allocation
+ * itself can be NOACCESS or UNDEFINED; our caller will soon make it
+ * UNDEFINED. Make extra space at the end of the chunk, if any,
+ * NOACCESS.
*/
- VALGRIND_MAKE_MEM_NOACCESS((char *) chunk + ALLOC_CHUNK_PUBLIC,
- chunk_size + ALLOC_CHUNKHDRSZ - ALLOC_CHUNK_PUBLIC);
+ VALGRIND_MAKE_MEM_NOACCESS((char *) chunk + ALLOC_CHUNKHDRSZ,
+ chunk_size - ALLOC_CHUNKHDRSZ);
return AllocChunkGetPointer(chunk);
}
chunk = (AllocChunk) (block->freeptr);
/* Prepare to initialize the chunk header. */
- VALGRIND_MAKE_MEM_UNDEFINED(chunk, ALLOC_CHUNK_USED);
+ VALGRIND_MAKE_MEM_UNDEFINED(chunk, ALLOC_CHUNKHDRSZ);
block->freeptr += (availchunk + ALLOC_CHUNKHDRSZ);
availspace -= (availchunk + ALLOC_CHUNKHDRSZ);
chunk = (AllocChunk) (block->freeptr);
/* Prepare to initialize the chunk header. */
- VALGRIND_MAKE_MEM_UNDEFINED(chunk, ALLOC_CHUNK_USED);
+ VALGRIND_MAKE_MEM_UNDEFINED(chunk, ALLOC_CHUNKHDRSZ);
block->freeptr += (chunk_size + ALLOC_CHUNKHDRSZ);
Assert(block->freeptr <= block->endptr);
Size
GetMemoryChunkSpace(void *pointer)
{
- StandardChunkHeader *header;
+ MemoryContext context = GetMemoryChunkContext(pointer);
- /*
- * Try to detect bogus pointers handed to us, poorly though we can.
- * Presumably, a pointer that isn't MAXALIGNED isn't pointing at an
- * allocated chunk.
- */
- Assert(pointer != NULL);
- Assert(pointer == (void *) MAXALIGN(pointer));
-
- /*
- * OK, it's probably safe to look at the chunk header.
- */
- header = (StandardChunkHeader *)
- ((char *) pointer - STANDARDCHUNKHEADERSIZE);
-
- AssertArg(MemoryContextIsValid(header->context));
-
- return (*header->context->methods->get_chunk_space) (header->context,
- pointer);
-}
-
-/*
- * GetMemoryChunkContext
- * Given a currently-allocated chunk, determine the context
- * it belongs to.
- */
-MemoryContext
-GetMemoryChunkContext(void *pointer)
-{
- StandardChunkHeader *header;
-
- /*
- * Try to detect bogus pointers handed to us, poorly though we can.
- * Presumably, a pointer that isn't MAXALIGNED isn't pointing at an
- * allocated chunk.
- */
- Assert(pointer != NULL);
- Assert(pointer == (void *) MAXALIGN(pointer));
-
- /*
- * OK, it's probably safe to look at the chunk header.
- */
- header = (StandardChunkHeader *)
- ((char *) pointer - STANDARDCHUNKHEADERSIZE);
-
- AssertArg(MemoryContextIsValid(header->context));
-
- return header->context;
+ return (context->methods->get_chunk_space) (context,
+ pointer);
}
/*
bool
MemoryContextContains(MemoryContext context, void *pointer)
{
- StandardChunkHeader *header;
-
- /*
- * Try to detect bogus pointers handed to us, poorly though we can.
- * Presumably, a pointer that isn't MAXALIGNED isn't pointing at an
- * allocated chunk.
- */
- if (pointer == NULL || pointer != (void *) MAXALIGN(pointer))
- return false;
+ MemoryContext ptr_context = GetMemoryChunkContext(pointer);
- /*
- * OK, it's probably safe to look at the chunk header.
- */
- header = (StandardChunkHeader *)
- ((char *) pointer - STANDARDCHUNKHEADERSIZE);
-
- return header->context == context;
+ return ptr_context == context;
}
/*--------------------
void
pfree(void *pointer)
{
- MemoryContext context;
-
- /*
- * Try to detect bogus pointers handed to us, poorly though we can.
- * Presumably, a pointer that isn't MAXALIGNED isn't pointing at an
- * allocated chunk.
- */
- Assert(pointer != NULL);
- Assert(pointer == (void *) MAXALIGN(pointer));
-
- /*
- * OK, it's probably safe to look at the chunk header.
- */
- context = ((StandardChunkHeader *)
- ((char *) pointer - STANDARDCHUNKHEADERSIZE))->context;
-
- AssertArg(MemoryContextIsValid(context));
+ MemoryContext context = GetMemoryChunkContext(pointer);
(*context->methods->free_p) (context, pointer);
VALGRIND_MEMPOOL_FREE(context, pointer);
void *
repalloc(void *pointer, Size size)
{
- MemoryContext context;
+ MemoryContext context = GetMemoryChunkContext(pointer);
void *ret;
if (!AllocSizeIsValid(size))
elog(ERROR, "invalid memory alloc request size %zu", size);
- /*
- * Try to detect bogus pointers handed to us, poorly though we can.
- * Presumably, a pointer that isn't MAXALIGNED isn't pointing at an
- * allocated chunk.
- */
- Assert(pointer != NULL);
- Assert(pointer == (void *) MAXALIGN(pointer));
-
- /*
- * OK, it's probably safe to look at the chunk header.
- */
- context = ((StandardChunkHeader *)
- ((char *) pointer - STANDARDCHUNKHEADERSIZE))->context;
-
- AssertArg(MemoryContextIsValid(context));
AssertNotInCriticalSection(context);
/* isReset must be false already */
void *
repalloc_huge(void *pointer, Size size)
{
- MemoryContext context;
+ MemoryContext context = GetMemoryChunkContext(pointer);
void *ret;
if (!AllocHugeSizeIsValid(size))
elog(ERROR, "invalid memory alloc request size %zu", size);
- /*
- * Try to detect bogus pointers handed to us, poorly though we can.
- * Presumably, a pointer that isn't MAXALIGNED isn't pointing at an
- * allocated chunk.
- */
- Assert(pointer != NULL);
- Assert(pointer == (void *) MAXALIGN(pointer));
-
- /*
- * OK, it's probably safe to look at the chunk header.
- */
- context = ((StandardChunkHeader *)
- ((char *) pointer - STANDARDCHUNKHEADERSIZE))->context;
-
- AssertArg(MemoryContextIsValid(context));
AssertNotInCriticalSection(context);
/* isReset must be false already */
#include "lib/ilist.h"
-#define SLAB_CHUNKHDRSZ MAXALIGN(sizeof(SlabChunk))
-
-/* Portion of SLAB_CHUNKHDRSZ excluding trailing padding. */
-#define SLAB_CHUNK_USED \
- (offsetof(SlabChunk, header) + sizeof(StandardChunkHeader))
-
/*
* SlabContext is a specialized implementation of MemoryContext.
*/
{
/* block owning this chunk */
void *block;
-
- /* include StandardChunkHeader because mcxt.c expects that */
- StandardChunkHeader header;
-
+ SlabContext *slab; /* owning context */
+ /* there must not be any padding to reach a MAXALIGN boundary here! */
} SlabChunk;
#define SlabPointerGetChunk(ptr) \
- ((SlabChunk *)(((char *)(ptr)) - SLAB_CHUNKHDRSZ))
+ ((SlabChunk *)(((char *)(ptr)) - sizeof(SlabChunk)))
#define SlabChunkGetPointer(chk) \
- ((void *)(((char *)(chk)) + SLAB_CHUNKHDRSZ))
+ ((void *)(((char *)(chk)) + sizeof(SlabChunk)))
#define SlabBlockGetChunk(slab, block, idx) \
((SlabChunk *) ((char *) (block) + sizeof(SlabBlock) \
+ (idx * slab->fullChunkSize)))
Size freelistSize;
SlabContext *slab;
+ StaticAssertStmt(offsetof(SlabChunk, slab) +sizeof(MemoryContext) ==
+ MAXALIGN(sizeof(SlabChunk)),
+ "padding calculation in SlabChunk is wrong");
+
/* otherwise the linked list inside freed chunk isn't guaranteed to fit */
StaticAssertStmt(MAXIMUM_ALIGNOF >= sizeof(int),
"MAXALIGN too small to fit int32");
/* Make sure the block can store at least one chunk. */
if (blockSize - sizeof(SlabBlock) < fullChunkSize)
- elog(ERROR, "block size %ld for slab is too small for %ld chunks",
+ elog(ERROR, "block size %zu for slab is too small for %zu chunks",
blockSize, chunkSize);
/* Compute maximum number of chunks per block */
/* make sure we only allow correct request size */
if (size != slab->chunkSize)
- elog(ERROR, "unexpected alloc chunk size %ld (expected %ld)",
+ elog(ERROR, "unexpected alloc chunk size %zu (expected %zu)",
size, slab->chunkSize);
/*
slab->minFreeChunks = 0;
/* Prepare to initialize the chunk header. */
- VALGRIND_MAKE_MEM_UNDEFINED(chunk, SLAB_CHUNK_USED);
+ VALGRIND_MAKE_MEM_UNDEFINED(chunk, sizeof(SlabChunk));
chunk->block = (void *) block;
-
- chunk->header.context = (MemoryContext) slab;
- chunk->header.size = MAXALIGN(size);
+ chunk->slab = slab;
#ifdef MEMORY_CONTEXT_CHECKING
- chunk->header.requested_size = size;
- VALGRIND_MAKE_MEM_NOACCESS(&chunk->header.requested_size,
- sizeof(chunk->header.requested_size));
/* slab mark to catch clobber of "unused" space */
- if (size < chunk->header.size)
+ if (slab->chunkSize < (slab->fullChunkSize - sizeof(SlabChunk)))
+ {
set_sentinel(SlabChunkGetPointer(chunk), size);
+ VALGRIND_MAKE_MEM_NOACCESS(((char *) chunk) +
+ sizeof(SlabChunk) + slab->chunkSize,
+ slab->fullChunkSize -
+ (slab->chunkSize + sizeof(SlabChunk)));
+ }
#endif
#ifdef RANDOMIZE_ALLOCATED_MEMORY
/* fill the allocated space with junk */
SlabFreeInfo(slab, chunk);
#ifdef MEMORY_CONTEXT_CHECKING
- VALGRIND_MAKE_MEM_DEFINED(&chunk->header.requested_size,
- sizeof(chunk->header.requested_size));
/* Test for someone scribbling on unused space in chunk */
- if (chunk->header.requested_size < chunk->header.size)
- if (!sentinel_ok(pointer, chunk->header.requested_size))
+ if (slab->chunkSize < (slab->fullChunkSize - sizeof(SlabChunk)))
+ if (!sentinel_ok(pointer, slab->chunkSize))
elog(WARNING, "detected write past chunk end in %s %p",
slab->header.name, chunk);
#endif
#ifdef CLOBBER_FREED_MEMORY
/* XXX don't wipe the int32 index, used for block-level freelist */
wipe_mem((char *) pointer + sizeof(int32),
- chunk->header.size - sizeof(int32));
-#endif
-
-#ifdef MEMORY_CONTEXT_CHECKING
- /* Reset requested_size to 0 in chunks that are on freelist */
- chunk->header.requested_size = 0;
+ slab->chunkSize - sizeof(int32));
#endif
/* remove the block from a freelist */
static Size
SlabGetChunkSpace(MemoryContext context, void *pointer)
{
- SlabChunk *chunk = SlabPointerGetChunk(pointer);
+ SlabContext *slab = castNode(SlabContext, context);
+
+ Assert(slab);
- return chunk->header.size + SLAB_CHUNKHDRSZ;
+ return slab->fullChunkSize;
}
/*
{
SlabChunk *chunk = SlabBlockGetChunk(slab, block, j);
- VALGRIND_MAKE_MEM_DEFINED(&chunk->header.requested_size,
- sizeof(chunk->header.requested_size));
-
- /* we're in a no-freelist branch */
- VALGRIND_MAKE_MEM_NOACCESS(&chunk->header.requested_size,
- sizeof(chunk->header.requested_size));
-
/* chunks have both block and slab pointers, so check both */
if (chunk->block != block)
elog(WARNING, "problem in slab %s: bogus block link in block %p, chunk %p",
name, block, chunk);
- if (chunk->header.context != (MemoryContext) slab)
+ if (chunk->slab != slab)
elog(WARNING, "problem in slab %s: bogus slab link in block %p, chunk %p",
name, block, chunk);
- /* now make sure the chunk size is correct */
- if (chunk->header.size != MAXALIGN(slab->chunkSize))
- elog(WARNING, "problem in slab %s: bogus chunk size in block %p, chunk %p",
- name, block, chunk);
-
- /* now make sure the chunk size is correct */
- if (chunk->header.requested_size != slab->chunkSize)
- elog(WARNING, "problem in slab %s: bogus chunk requested size in block %p, chunk %p",
- name, block, chunk);
-
/* there might be sentinel (thanks to alignment) */
- if (chunk->header.requested_size < chunk->header.size &&
- !sentinel_ok(chunk, SLAB_CHUNKHDRSZ + chunk->header.requested_size))
- elog(WARNING, "problem in slab %s: detected write past chunk end in block %p, chunk %p",
- name, block, chunk);
+ if (slab->chunkSize < (slab->fullChunkSize - sizeof(SlabChunk)))
+ if (!sentinel_ok(chunk, slab->chunkSize))
+ elog(WARNING, "problem in slab %s: detected write past chunk end in block %p, chunk %p",
+ name, block, chunk);
}
}
#define AllocHugeSizeIsValid(size) ((Size) (size) <= MaxAllocHugeSize)
-/*
- * All chunks allocated by any memory context manager are required to be
- * preceded by a StandardChunkHeader at a spacing of STANDARDCHUNKHEADERSIZE.
- * A currently-allocated chunk must contain a backpointer to its owning
- * context as well as the allocated size of the chunk. The backpointer is
- * used by pfree() and repalloc() to find the context to call. The allocated
- * size is not absolutely essential, but it's expected to be needed by any
- * reasonable implementation.
- */
-typedef struct StandardChunkHeader
-{
- MemoryContext context; /* owning context */
- Size size; /* size of data space allocated in chunk */
-#ifdef MEMORY_CONTEXT_CHECKING
- /* when debugging memory usage, also store actual requested size */
- Size requested_size;
-#endif
-} StandardChunkHeader;
-
-#define STANDARDCHUNKHEADERSIZE MAXALIGN(sizeof(StandardChunkHeader))
-
/*
* Standard top-level memory contexts.
extern void MemoryContextSetParent(MemoryContext context,
MemoryContext new_parent);
extern Size GetMemoryChunkSpace(void *pointer);
-extern MemoryContext GetMemoryChunkContext(void *pointer);
extern MemoryContext MemoryContextGetParent(MemoryContext context);
extern bool MemoryContextIsEmpty(MemoryContext context);
extern void MemoryContextStats(MemoryContext context);
#endif
extern bool MemoryContextContains(MemoryContext context, void *pointer);
+/*
+ * GetMemoryChunkContext
+ * Given a currently-allocated chunk, determine the context
+ * it belongs to.
+ *
+ * All chunks allocated by any memory context manager are required to be
+ * preceded by the corresponding MemoryContext stored, without padding, in the
+ * preceding sizeof(void*) bytes. A currently-allocated chunk must contain a
+ * backpointer to its owning context. The backpointer is used by pfree() and
+ * repalloc() to find the context to call.
+ */
+#ifndef FRONTEND
+static inline MemoryContext
+GetMemoryChunkContext(void *pointer)
+{
+ MemoryContext context;
+
+ /*
+ * Try to detect bogus pointers handed to us, poorly though we can.
+ * Presumably, a pointer that isn't MAXALIGNED isn't pointing at an
+ * allocated chunk.
+ */
+ Assert(pointer != NULL);
+ Assert(pointer == (void *) MAXALIGN(pointer));
+
+ /*
+ * OK, it's probably safe to look at the context.
+ */
+ context = *(MemoryContext *) (((char *) pointer) - sizeof(void *));
+
+ AssertArg(MemoryContextIsValid(context));
+
+ return context;
+}
+#endif
+
/*
* This routine handles the context-type-independent part of memory
* context creation. It's intended to be called from context-type-
SplitVar
SplitedPageLayout
StackElem
-StandardChunkHeader
StartBlobPtr
StartBlobsPtr
StartDataPtr