PostgreSQL Source Code: src/backend/utils/mmgr/alignedalloc.c Source File

PostgreSQL Source Code git master
alignedalloc.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * alignedalloc.c
4 * Allocator functions to implement palloc_aligned
5 *
6 * This is not a fully-fledged MemoryContext type as there is no means to
7 * create a MemoryContext of this type. The code here only serves to allow
8 * operations such as pfree() and repalloc() to work correctly on a memory
9 * chunk that was allocated by palloc_aligned().
10 *
11 * Portions Copyright (c) 2022-2025, PostgreSQL Global Development Group
12 *
13 * IDENTIFICATION
14 * src/backend/utils/mmgr/alignedalloc.c
15 *
16 *-------------------------------------------------------------------------
17 */
18
19#include "postgres.h"
20
21#include "utils/memdebug.h"
22#include "utils/memutils_memorychunk.h"
23
24/*
25 * AlignedAllocFree
26* Frees allocated memory; memory is removed from its owning context.
27*/
28void
29 AlignedAllocFree(void *pointer)
30{
31 MemoryChunk *chunk = PointerGetMemoryChunk(pointer);
32 void *unaligned;
33
34 VALGRIND_MAKE_MEM_DEFINED(chunk, sizeof(MemoryChunk));
35
36 Assert(!MemoryChunkIsExternal(chunk));
37
38 /* obtain the original (unaligned) allocated pointer */
39 unaligned = MemoryChunkGetBlock(chunk);
40
41#ifdef MEMORY_CONTEXT_CHECKING
42 /* Test for someone scribbling on unused space in chunk */
43 if (!sentinel_ok(pointer, chunk->requested_size))
44 elog(WARNING, "detected write past chunk end in %s %p",
45 GetMemoryChunkContext(unaligned)->name, chunk);
46#endif
47
48 /*
49 * Create a dummy vchunk covering the start of the unaligned chunk, but
50 * not overlapping the aligned chunk. This will be freed while pfree'ing
51 * the unaligned chunk, keeping Valgrind happy. Then when we return to
52 * the outer pfree, that will clean up the vchunk for the aligned chunk.
53 */
54 VALGRIND_MEMPOOL_ALLOC(GetMemoryChunkContext(unaligned), unaligned,
55 (char *) pointer - (char *) unaligned);
56
57 /* Recursively pfree the unaligned chunk */
58 pfree(unaligned);
59}
60
61/*
62 * AlignedAllocRealloc
63 * Change the allocated size of a chunk and return possibly a different
64 * pointer to a memory address aligned to the same boundary as the
65 * originally requested alignment. The contents of 'pointer' will be
66 * copied into the returned pointer up until 'size'. Any additional
67 * memory will be uninitialized.
68 */
69void *
70 AlignedAllocRealloc(void *pointer, Size size, int flags)
71{
72 MemoryChunk *redirchunk = PointerGetMemoryChunk(pointer);
73 Size alignto;
74 void *unaligned;
75 MemoryContext ctx;
76 Size old_size;
77 void *newptr;
78
79 VALGRIND_MAKE_MEM_DEFINED(redirchunk, sizeof(MemoryChunk));
80
81 alignto = MemoryChunkGetValue(redirchunk);
82 unaligned = MemoryChunkGetBlock(redirchunk);
83
84 /* sanity check this is a power of 2 value */
85 Assert((alignto & (alignto - 1)) == 0);
86
87 /*
88 * Determine the size of the original allocation. We can't determine this
89 * exactly as GetMemoryChunkSpace() returns the total space used for the
90 * allocation, which for contexts like aset includes rounding up to the
91 * next power of 2. However, this value is just used to memcpy() the old
92 * data into the new allocation, so we only need to concern ourselves with
93 * not reading beyond the end of the original allocation's memory. The
94 * drawback here is that we may copy more bytes than we need to, which
95 * only amounts to wasted effort. We can safely subtract the extra bytes
96 * that we requested to allow us to align the pointer. We must also
97 * subtract the space for the unaligned pointer's MemoryChunk since
98 * GetMemoryChunkSpace should have included that. This does assume that
99 * all context types use MemoryChunk as a chunk header.
100 */
101 old_size = GetMemoryChunkSpace(unaligned) -
102 PallocAlignedExtraBytes(alignto) - sizeof(MemoryChunk);
103
104#ifdef MEMORY_CONTEXT_CHECKING
105 /* check that GetMemoryChunkSpace returned something realistic */
106 Assert(old_size >= redirchunk->requested_size);
107#endif
108
109 /*
110 * To keep things simple, we always allocate a new aligned chunk and copy
111 * data into it. Because of the above inaccuracy, this may end in copying
112 * more data than was in the original allocation request size, but that
113 * should be OK.
114 */
115 ctx = GetMemoryChunkContext(unaligned);
116 newptr = MemoryContextAllocAligned(ctx, size, alignto, flags);
117
118 /* Cope cleanly with OOM */
119 if (unlikely(newptr == NULL))
120 {
121 VALGRIND_MAKE_MEM_NOACCESS(redirchunk, sizeof(MemoryChunk));
122 return MemoryContextAllocationFailure(ctx, size, flags);
123 }
124
125 /*
126 * We may memcpy more than the original allocation request size, which
127 * would result in trying to copy trailing bytes that the original
128 * MemoryContextAllocAligned call marked NOACCESS. So we must mark the
129 * entire old_size as defined. That's slightly annoying, but probably not
130 * worth improving.
131 */
132 VALGRIND_MAKE_MEM_DEFINED(pointer, old_size);
133 memcpy(newptr, pointer, Min(size, old_size));
134
135 /*
136 * Create a dummy vchunk covering the start of the old unaligned chunk,
137 * but not overlapping the aligned chunk. This will be freed while
138 * pfree'ing the old unaligned chunk, keeping Valgrind happy. Then when
139 * we return to repalloc, it will move the vchunk for the aligned chunk.
140 */
141 VALGRIND_MEMPOOL_ALLOC(ctx, unaligned,
142 (char *) pointer - (char *) unaligned);
143
144 pfree(unaligned);
145
146 return newptr;
147}
148
149/*
150 * AlignedAllocGetChunkContext
151 * Return the MemoryContext that 'pointer' belongs to.
152 */
153MemoryContext
154 AlignedAllocGetChunkContext(void *pointer)
155{
156 MemoryChunk *redirchunk = PointerGetMemoryChunk(pointer);
157 MemoryContext cxt;
158
159 VALGRIND_MAKE_MEM_DEFINED(redirchunk, sizeof(MemoryChunk));
160
161 Assert(!MemoryChunkIsExternal(redirchunk));
162
163 cxt = GetMemoryChunkContext(MemoryChunkGetBlock(redirchunk));
164
165 VALGRIND_MAKE_MEM_NOACCESS(redirchunk, sizeof(MemoryChunk));
166
167 return cxt;
168}
169
170/*
171 * AlignedAllocGetChunkSpace
172 * Given a currently-allocated chunk, determine the total space
173 * it occupies (including all memory-allocation overhead).
174 */
175Size
176 AlignedAllocGetChunkSpace(void *pointer)
177{
178 MemoryChunk *redirchunk = PointerGetMemoryChunk(pointer);
179 void *unaligned;
180 Size space;
181
182 VALGRIND_MAKE_MEM_DEFINED(redirchunk, sizeof(MemoryChunk));
183
184 unaligned = MemoryChunkGetBlock(redirchunk);
185 space = GetMemoryChunkSpace(unaligned);
186
187 VALGRIND_MAKE_MEM_NOACCESS(redirchunk, sizeof(MemoryChunk));
188
189 return space;
190}
MemoryContext AlignedAllocGetChunkContext(void *pointer)
Definition: alignedalloc.c:154
void * AlignedAllocRealloc(void *pointer, Size size, int flags)
Definition: alignedalloc.c:70
Size AlignedAllocGetChunkSpace(void *pointer)
Definition: alignedalloc.c:176
void AlignedAllocFree(void *pointer)
Definition: alignedalloc.c:29
#define Min(x, y)
Definition: c.h:1003
#define unlikely(x)
Definition: c.h:402
size_t Size
Definition: c.h:610
#define WARNING
Definition: elog.h:36
#define elog(elevel,...)
Definition: elog.h:226
Assert(PointerIsAligned(start, uint64))
void pfree(void *pointer)
Definition: mcxt.c:1594
Size GetMemoryChunkSpace(void *pointer)
Definition: mcxt.c:767
void * MemoryContextAllocAligned(MemoryContext context, Size size, Size alignto, int flags)
Definition: mcxt.c:1460
MemoryContext GetMemoryChunkContext(void *pointer)
Definition: mcxt.c:753
void * MemoryContextAllocationFailure(MemoryContext context, Size size, int flags)
Definition: mcxt.c:1195
#define VALGRIND_MAKE_MEM_DEFINED(addr, size)
Definition: memdebug.h:26
#define VALGRIND_MEMPOOL_ALLOC(context, addr, size)
Definition: memdebug.h:29
#define VALGRIND_MAKE_MEM_NOACCESS(addr, size)
Definition: memdebug.h:27
#define PallocAlignedExtraBytes(alignto)
static Size MemoryChunkGetValue(MemoryChunk *chunk)
static bool MemoryChunkIsExternal(MemoryChunk *chunk)
static void * MemoryChunkGetBlock(MemoryChunk *chunk)
struct MemoryChunk MemoryChunk
#define PointerGetMemoryChunk(p)
const char * name

AltStyle によって変換されたページ (->オリジナル) /