Skip to content

Commit f65d21b

Browse files
committed
Mostly-cosmetic improvements in memory chunk header alignment coding.
Add commentary about what we're doing and why. Apply the method used for padding in GenerationChunk to AllocChunkData, replacing the rather ad-hoc solution used in commit 7e3aa03. Reorder fields in GenerationChunk so that the padding calculation will work even if sizeof(size_t) is different from sizeof(void *) --- likely that will never happen, but we don't need the assumption if we do it like this. Improve static assertions about alignment. In passing, fix a couple of oversights in the "large chunk" path in GenerationAlloc(). Discussion: https://postgr.es/m/E1eHa4J-0006hI-Q8@gemulon.postgresql.org
1 parent cc3c4af commit f65d21b

File tree

3 files changed

+62
-42
lines changed

3 files changed

+62
-42
lines changed

src/backend/utils/mmgr/aset.c

+20-5
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,14 @@ typedef struct AllocBlockData
157157
/*
158158
* AllocChunk
159159
* The prefix of each piece of memory in an AllocBlock
160+
*
161+
* Note: to meet the memory context APIs, the payload area of the chunk must
162+
* be maxaligned, and the "aset" link must be immediately adjacent to the
163+
* payload area (cf. GetMemoryChunkContext). We simplify matters for this
164+
* module by requiring sizeof(AllocChunkData) to be maxaligned, and then
165+
* we can ensure things work by adding any required alignment padding before
166+
* the "aset" field. There is a static assertion below that the alignment
167+
* is done correctly.
160168
*/
161169
typedef struct AllocChunkData
162170
{
@@ -166,15 +174,19 @@ typedef struct AllocChunkData
166174
/* when debugging memory usage, also store actual requested size */
167175
/* this is zero in a free chunk */
168176
Size requested_size;
169-
#if MAXIMUM_ALIGNOF > 4 && SIZEOF_VOID_P == 4
170-
Size padding;
171-
#endif
172177

178+
#define ALLOCCHUNK_RAWSIZE (SIZEOF_SIZE_T * 2 + SIZEOF_VOID_P)
179+
#else
180+
#define ALLOCCHUNK_RAWSIZE (SIZEOF_SIZE_T + SIZEOF_VOID_P)
173181
#endif /* MEMORY_CONTEXT_CHECKING */
174182

183+
/* ensure proper alignment by adding padding if needed */
184+
#if (ALLOCCHUNK_RAWSIZE % MAXIMUM_ALIGNOF) != 0
185+
char padding[MAXIMUM_ALIGNOF - ALLOCCHUNK_RAWSIZE % MAXIMUM_ALIGNOF];
186+
#endif
187+
175188
/* aset is the owning aset if allocated, or the freelist link if free */
176189
void *aset;
177-
178190
/* there must not be any padding to reach a MAXALIGN boundary here! */
179191
} AllocChunkData;
180192

@@ -327,8 +339,11 @@ AllocSetContextCreate(MemoryContext parent,
327339
{
328340
AllocSet set;
329341

342+
/* Assert we padded AllocChunkData properly */
343+
StaticAssertStmt(ALLOC_CHUNKHDRSZ == MAXALIGN(ALLOC_CHUNKHDRSZ),
344+
"sizeof(AllocChunkData) is not maxaligned");
330345
StaticAssertStmt(offsetof(AllocChunkData, aset) + sizeof(MemoryContext) ==
331-
MAXALIGN(sizeof(AllocChunkData)),
346+
ALLOC_CHUNKHDRSZ,
332347
"padding calculation in AllocChunkData is wrong");
333348

334349
/*

src/backend/utils/mmgr/generation.c

+27-31
Original file line numberDiff line numberDiff line change
@@ -46,19 +46,6 @@
4646
#define Generation_BLOCKHDRSZ MAXALIGN(sizeof(GenerationBlock))
4747
#define Generation_CHUNKHDRSZ sizeof(GenerationChunk)
4848

49-
/* Portion of Generation_CHUNKHDRSZ examined outside generation.c. */
50-
#define Generation_CHUNK_PUBLIC \
51-
(offsetof(GenerationChunk, size) + sizeof(Size))
52-
53-
/* Portion of Generation_CHUNKHDRSZ excluding trailing padding. */
54-
#ifdef MEMORY_CONTEXT_CHECKING
55-
#define Generation_CHUNK_USED \
56-
(offsetof(GenerationChunk, requested_size) + sizeof(Size))
57-
#else
58-
#define Generation_CHUNK_USED \
59-
(offsetof(GenerationChunk, size) + sizeof(Size))
60-
#endif
61-
6249
typedef struct GenerationBlock GenerationBlock; /* forward reference */
6350
typedef struct GenerationChunk GenerationChunk;
6451

@@ -103,28 +90,35 @@ struct GenerationBlock
10390
/*
10491
* GenerationChunk
10592
* The prefix of each piece of memory in a GenerationBlock
93+
*
94+
* Note: to meet the memory context APIs, the payload area of the chunk must
95+
* be maxaligned, and the "context" link must be immediately adjacent to the
96+
* payload area (cf. GetMemoryChunkContext). We simplify matters for this
97+
* module by requiring sizeof(GenerationChunk) to be maxaligned, and then
98+
* we can ensure things work by adding any required alignment padding before
99+
* the pointer fields. There is a static assertion below that the alignment
100+
* is done correctly.
106101
*/
107102
struct GenerationChunk
108103
{
109-
/* block owning this chunk */
110-
void *block;
111-
112104
/* size is always the size of the usable space in the chunk */
113105
Size size;
114106
#ifdef MEMORY_CONTEXT_CHECKING
115107
/* when debugging memory usage, also store actual requested size */
116108
/* this is zero in a free chunk */
117109
Size requested_size;
118-
#define GENERATIONCHUNK_RAWSIZE (SIZEOF_VOID_P * 2 + SIZEOF_SIZE_T * 2)
110+
111+
#define GENERATIONCHUNK_RAWSIZE (SIZEOF_SIZE_T * 2 + SIZEOF_VOID_P * 2)
119112
#else
120-
#define GENERATIONCHUNK_RAWSIZE (SIZEOF_VOID_P * 2 + SIZEOF_SIZE_T)
113+
#define GENERATIONCHUNK_RAWSIZE (SIZEOF_SIZE_T + SIZEOF_VOID_P * 2)
121114
#endif /* MEMORY_CONTEXT_CHECKING */
122115

123116
/* ensure proper alignment by adding padding if needed */
124117
#if (GENERATIONCHUNK_RAWSIZE % MAXIMUM_ALIGNOF) != 0
125-
char padding[MAXIMUM_ALIGNOF - (GENERATIONCHUNK_RAWSIZE % MAXIMUM_ALIGNOF)];
118+
char padding[MAXIMUM_ALIGNOF - GENERATIONCHUNK_RAWSIZE % MAXIMUM_ALIGNOF];
126119
#endif
127120

121+
GenerationBlock *block; /* block owning this chunk */
128122
GenerationContext *context; /* owning context */
129123
/* there must not be any padding to reach a MAXALIGN boundary here! */
130124
};
@@ -210,8 +204,11 @@ GenerationContextCreate(MemoryContext parent,
210204
{
211205
GenerationContext *set;
212206

207+
/* Assert we padded GenerationChunk properly */
208+
StaticAssertStmt(Generation_CHUNKHDRSZ == MAXALIGN(Generation_CHUNKHDRSZ),
209+
"sizeof(GenerationChunk) is not maxaligned");
213210
StaticAssertStmt(offsetof(GenerationChunk, context) + sizeof(MemoryContext) ==
214-
MAXALIGN(sizeof(GenerationChunk)),
211+
Generation_CHUNKHDRSZ,
215212
"padding calculation in GenerationChunk is wrong");
216213

217214
/*
@@ -318,7 +315,6 @@ GenerationAlloc(MemoryContext context, Size size)
318315
GenerationContext *set = (GenerationContext *) context;
319316
GenerationBlock *block;
320317
GenerationChunk *chunk;
321-
322318
Size chunk_size = MAXALIGN(size);
323319

324320
/* is it an over-sized chunk? if yes, allocate special block */
@@ -338,6 +334,7 @@ GenerationAlloc(MemoryContext context, Size size)
338334
block->freeptr = block->endptr = ((char *) block) + blksize;
339335

340336
chunk = (GenerationChunk *) (((char *) block) + Generation_BLOCKHDRSZ);
337+
chunk->block = block;
341338
chunk->context = set;
342339
chunk->size = chunk_size;
343340

@@ -356,17 +353,16 @@ GenerationAlloc(MemoryContext context, Size size)
356353
/* add the block to the list of allocated blocks */
357354
dlist_push_head(&set->blocks, &block->node);
358355

359-
GenerationAllocInfo(set, chunk);
360-
361356
/*
362-
* Chunk header public fields remain DEFINED. The requested
363-
* allocation itself can be NOACCESS or UNDEFINED; our caller will
364-
* soon make it UNDEFINED. Make extra space at the end of the chunk,
365-
* if any, NOACCESS.
357+
* Chunk header fields remain DEFINED. The requested allocation
358+
* itself can be NOACCESS or UNDEFINED; our caller will soon make it
359+
* UNDEFINED. Make extra space at the end of the chunk, if any,
360+
* NOACCESS.
366361
*/
367-
VALGRIND_MAKE_MEM_NOACCESS((char *) chunk + Generation_CHUNK_PUBLIC,
368-
chunk_size + Generation_CHUNKHDRSZ - Generation_CHUNK_PUBLIC);
362+
VALGRIND_MAKE_MEM_NOACCESS((char *) chunk + Generation_CHUNKHDRSZ + size,
363+
chunk_size - size);
369364

365+
GenerationAllocInfo(set, chunk);
370366
return GenerationChunkGetPointer(chunk);
371367
}
372368

@@ -442,8 +438,8 @@ GenerationAlloc(MemoryContext context, Size size)
442438

443439
/*
444440
* GenerationFree
445-
* Update number of chunks on the block, and if all chunks on the block
446-
* are freeed then discard the block.
441+
* Update number of chunks in the block, and if all chunks in the block
442+
* are now free then discard the block.
447443
*/
448444
static void
449445
GenerationFree(MemoryContext context, void *pointer)

src/backend/utils/mmgr/slab.c

+15-6
Original file line numberDiff line numberDiff line change
@@ -91,12 +91,18 @@ typedef struct SlabBlock
9191

9292
/*
9393
* SlabChunk
94-
* The prefix of each piece of memory in an SlabBlock
94+
* The prefix of each piece of memory in a SlabBlock
95+
*
96+
* Note: to meet the memory context APIs, the payload area of the chunk must
97+
* be maxaligned, and the "slab" link must be immediately adjacent to the
98+
* payload area (cf. GetMemoryChunkContext). Since we support no machines on
99+
* which MAXALIGN is more than twice sizeof(void *), this happens without any
100+
* special hacking in this struct declaration. But there is a static
101+
* assertion below that the alignment is done correctly.
95102
*/
96103
typedef struct SlabChunk
97104
{
98-
/* block owning this chunk */
99-
void *block;
105+
SlabBlock *block; /* block owning this chunk */
100106
SlabContext *slab; /* owning context */
101107
/* there must not be any padding to reach a MAXALIGN boundary here! */
102108
} SlabChunk;
@@ -190,16 +196,19 @@ SlabContextCreate(MemoryContext parent,
190196
Size freelistSize;
191197
SlabContext *slab;
192198

199+
/* Assert we padded SlabChunk properly */
200+
StaticAssertStmt(sizeof(SlabChunk) == MAXALIGN(sizeof(SlabChunk)),
201+
"sizeof(SlabChunk) is not maxaligned");
193202
StaticAssertStmt(offsetof(SlabChunk, slab) + sizeof(MemoryContext) ==
194-
MAXALIGN(sizeof(SlabChunk)),
203+
sizeof(SlabChunk),
195204
"padding calculation in SlabChunk is wrong");
196205

197206
/* Make sure the linked list node fits inside a freed chunk */
198207
if (chunkSize < sizeof(int))
199208
chunkSize = sizeof(int);
200209

201210
/* chunk, including SLAB header (both addresses nicely aligned) */
202-
fullChunkSize = MAXALIGN(sizeof(SlabChunk) + MAXALIGN(chunkSize));
211+
fullChunkSize = sizeof(SlabChunk) + MAXALIGN(chunkSize);
203212

204213
/* Make sure the block can store at least one chunk. */
205214
if (blockSize - sizeof(SlabBlock) < fullChunkSize)
@@ -443,7 +452,7 @@ SlabAlloc(MemoryContext context, Size size)
443452
/* Prepare to initialize the chunk header. */
444453
VALGRIND_MAKE_MEM_UNDEFINED(chunk, sizeof(SlabChunk));
445454

446-
chunk->block = (void *) block;
455+
chunk->block = block;
447456
chunk->slab = slab;
448457

449458
#ifdef MEMORY_CONTEXT_CHECKING

0 commit comments

Comments
 (0)