/*
* AllocChunk
* The prefix of each piece of memory in an AllocBlock
+ *
+ * Note: to meet the memory context APIs, the payload area of the chunk must
+ * be maxaligned, and the "aset" link must be immediately adjacent to the
+ * payload area (cf. GetMemoryChunkContext). We simplify matters for this
+ * module by requiring sizeof(AllocChunkData) to be maxaligned, and then
+ * we can ensure things work by adding any required alignment padding before
+ * the "aset" field. There is a static assertion below that the alignment
+ * is done correctly.
*/
typedef struct AllocChunkData
{
/* 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
+#define ALLOCCHUNK_RAWSIZE (SIZEOF_SIZE_T * 2 + SIZEOF_VOID_P)
+#else
+#define ALLOCCHUNK_RAWSIZE (SIZEOF_SIZE_T + SIZEOF_VOID_P)
#endif /* MEMORY_CONTEXT_CHECKING */
+ /* ensure proper alignment by adding padding if needed */
+#if (ALLOCCHUNK_RAWSIZE % MAXIMUM_ALIGNOF) != 0
+ char padding[MAXIMUM_ALIGNOF - ALLOCCHUNK_RAWSIZE % MAXIMUM_ALIGNOF];
+#endif
+
/* 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;
+ /* Assert we padded AllocChunkData properly */
+ StaticAssertStmt(ALLOC_CHUNKHDRSZ == MAXALIGN(ALLOC_CHUNKHDRSZ),
+ "sizeof(AllocChunkData) is not maxaligned");
StaticAssertStmt(offsetof(AllocChunkData, aset) + sizeof(MemoryContext) ==
- MAXALIGN(sizeof(AllocChunkData)),
+ ALLOC_CHUNKHDRSZ,
"padding calculation in AllocChunkData is wrong");
/*
#define Generation_BLOCKHDRSZ MAXALIGN(sizeof(GenerationBlock))
#define Generation_CHUNKHDRSZ sizeof(GenerationChunk)
-/* Portion of Generation_CHUNKHDRSZ examined outside generation.c. */
-#define Generation_CHUNK_PUBLIC \
- (offsetof(GenerationChunk, size) + sizeof(Size))
-
-/* Portion of Generation_CHUNKHDRSZ excluding trailing padding. */
-#ifdef MEMORY_CONTEXT_CHECKING
-#define Generation_CHUNK_USED \
- (offsetof(GenerationChunk, requested_size) + sizeof(Size))
-#else
-#define Generation_CHUNK_USED \
- (offsetof(GenerationChunk, size) + sizeof(Size))
-#endif
-
typedef struct GenerationBlock GenerationBlock; /* forward reference */
typedef struct GenerationChunk GenerationChunk;
/*
* GenerationChunk
* The prefix of each piece of memory in a GenerationBlock
+ *
+ * Note: to meet the memory context APIs, the payload area of the chunk must
+ * be maxaligned, and the "context" link must be immediately adjacent to the
+ * payload area (cf. GetMemoryChunkContext). We simplify matters for this
+ * module by requiring sizeof(GenerationChunk) to be maxaligned, and then
+ * we can ensure things work by adding any required alignment padding before
+ * the pointer fields. There is a static assertion below that the alignment
+ * is done correctly.
*/
struct GenerationChunk
{
- /* block owning this chunk */
- void *block;
-
/* 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;
-#define GENERATIONCHUNK_RAWSIZE (SIZEOF_VOID_P * 2 + SIZEOF_SIZE_T * 2)
+
+#define GENERATIONCHUNK_RAWSIZE (SIZEOF_SIZE_T * 2 + SIZEOF_VOID_P * 2)
#else
-#define GENERATIONCHUNK_RAWSIZE (SIZEOF_VOID_P * 2 + SIZEOF_SIZE_T)
+#define GENERATIONCHUNK_RAWSIZE (SIZEOF_SIZE_T + SIZEOF_VOID_P * 2)
#endif /* MEMORY_CONTEXT_CHECKING */
/* ensure proper alignment by adding padding if needed */
#if (GENERATIONCHUNK_RAWSIZE % MAXIMUM_ALIGNOF) != 0
- char padding[MAXIMUM_ALIGNOF - (GENERATIONCHUNK_RAWSIZE % MAXIMUM_ALIGNOF)];
+ char padding[MAXIMUM_ALIGNOF - GENERATIONCHUNK_RAWSIZE % MAXIMUM_ALIGNOF];
#endif
+ GenerationBlock *block; /* block owning this chunk */
GenerationContext *context; /* owning context */
/* there must not be any padding to reach a MAXALIGN boundary here! */
};
{
GenerationContext *set;
+ /* Assert we padded GenerationChunk properly */
+ StaticAssertStmt(Generation_CHUNKHDRSZ == MAXALIGN(Generation_CHUNKHDRSZ),
+ "sizeof(GenerationChunk) is not maxaligned");
StaticAssertStmt(offsetof(GenerationChunk, context) + sizeof(MemoryContext) ==
- MAXALIGN(sizeof(GenerationChunk)),
+ Generation_CHUNKHDRSZ,
"padding calculation in GenerationChunk is wrong");
/*
GenerationContext *set = (GenerationContext *) context;
GenerationBlock *block;
GenerationChunk *chunk;
-
Size chunk_size = MAXALIGN(size);
/* is it an over-sized chunk? if yes, allocate special block */
block->freeptr = block->endptr = ((char *) block) + blksize;
chunk = (GenerationChunk *) (((char *) block) + Generation_BLOCKHDRSZ);
+ chunk->block = block;
chunk->context = set;
chunk->size = chunk_size;
/* add the block to the list of allocated blocks */
dlist_push_head(&set->blocks, &block->node);
- GenerationAllocInfo(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 header 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 + Generation_CHUNK_PUBLIC,
- chunk_size + Generation_CHUNKHDRSZ - Generation_CHUNK_PUBLIC);
+ VALGRIND_MAKE_MEM_NOACCESS((char *) chunk + Generation_CHUNKHDRSZ + size,
+ chunk_size - size);
+ GenerationAllocInfo(set, chunk);
return GenerationChunkGetPointer(chunk);
}
/*
* GenerationFree
- * Update number of chunks on the block, and if all chunks on the block
- * are freeed then discard the block.
+ * Update number of chunks in the block, and if all chunks in the block
+ * are now free then discard the block.
*/
static void
GenerationFree(MemoryContext context, void *pointer)
/*
* SlabChunk
- * The prefix of each piece of memory in an SlabBlock
+ * The prefix of each piece of memory in a SlabBlock
+ *
+ * Note: to meet the memory context APIs, the payload area of the chunk must
+ * be maxaligned, and the "slab" link must be immediately adjacent to the
+ * payload area (cf. GetMemoryChunkContext). Since we support no machines on
+ * which MAXALIGN is more than twice sizeof(void *), this happens without any
+ * special hacking in this struct declaration. But there is a static
+ * assertion below that the alignment is done correctly.
*/
typedef struct SlabChunk
{
- /* block owning this chunk */
- void *block;
+ SlabBlock *block; /* block owning this chunk */
SlabContext *slab; /* owning context */
/* there must not be any padding to reach a MAXALIGN boundary here! */
} SlabChunk;
Size freelistSize;
SlabContext *slab;
+ /* Assert we padded SlabChunk properly */
+ StaticAssertStmt(sizeof(SlabChunk) == MAXALIGN(sizeof(SlabChunk)),
+ "sizeof(SlabChunk) is not maxaligned");
StaticAssertStmt(offsetof(SlabChunk, slab) + sizeof(MemoryContext) ==
- MAXALIGN(sizeof(SlabChunk)),
+ sizeof(SlabChunk),
"padding calculation in SlabChunk is wrong");
/* Make sure the linked list node fits inside a freed chunk */
chunkSize = sizeof(int);
/* chunk, including SLAB header (both addresses nicely aligned) */
- fullChunkSize = MAXALIGN(sizeof(SlabChunk) + MAXALIGN(chunkSize));
+ fullChunkSize = sizeof(SlabChunk) + MAXALIGN(chunkSize);
/* Make sure the block can store at least one chunk. */
if (blockSize - sizeof(SlabBlock) < fullChunkSize)
/* Prepare to initialize the chunk header. */
VALGRIND_MAKE_MEM_UNDEFINED(chunk, sizeof(SlabChunk));
- chunk->block = (void *) block;
+ chunk->block = block;
chunk->slab = slab;
#ifdef MEMORY_CONTEXT_CHECKING