Branch data Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * mcxt.c
4 : : * POSTGRES memory context management code.
5 : : *
6 : : * This module handles context management operations that are independent
7 : : * of the particular kind of context being operated on. It calls
8 : : * context-type-specific operations via the function pointers in a
9 : : * context's MemoryContextMethods struct.
10 : : *
11 : : * A note about Valgrind support: when USE_VALGRIND is defined, we provide
12 : : * support for memory leak tracking at the allocation-unit level. Valgrind
13 : : * does leak detection by tracking allocated "chunks", which can be grouped
14 : : * into "pools". The "chunk" terminology is overloaded, since we use that
15 : : * word for our allocation units, and it's sometimes important to distinguish
16 : : * those from the Valgrind objects that describe them. To reduce confusion,
17 : : * let's use the terms "vchunk" and "vpool" for the Valgrind objects.
18 : : *
19 : : * We use a separate vpool for each memory context. The context-type-specific
20 : : * code is responsible for creating and deleting the vpools, and also for
21 : : * creating vchunks to cover its management data structures such as block
22 : : * headers. (There must be a vchunk that includes every pointer we want
23 : : * Valgrind to consider for leak-tracking purposes.) This module creates
24 : : * and deletes the vchunks that cover the caller-visible allocated chunks.
25 : : * However, the context-type-specific code must handle cleaning up those
26 : : * vchunks too during memory context reset operations.
27 : : *
28 : : *
29 : : * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
30 : : * Portions Copyright (c) 1994, Regents of the University of California
31 : : *
32 : : *
33 : : * IDENTIFICATION
34 : : * src/backend/utils/mmgr/mcxt.c
35 : : *
36 : : *-------------------------------------------------------------------------
37 : : */
38 : :
39 : : #include "postgres.h"
40 : :
41 : : #include "mb/pg_wchar.h"
42 : : #include "miscadmin.h"
43 : : #include "utils/memdebug.h"
44 : : #include "utils/memutils.h"
45 : : #include "utils/memutils_internal.h"
46 : : #include "utils/memutils_memorychunk.h"
47 : :
48 : :
49 : : static void BogusFree(void *pointer);
50 : : static void *BogusRealloc(void *pointer, Size size, int flags);
51 : : static MemoryContext BogusGetChunkContext(void *pointer);
52 : : static Size BogusGetChunkSpace(void *pointer);
53 : :
54 : : /*****************************************************************************
55 : : * GLOBAL MEMORY *
56 : : *****************************************************************************/
57 : : #define BOGUS_MCTX(id) \
58 : : [id].free_p = BogusFree, \
59 : : [id].realloc = BogusRealloc, \
60 : : [id].get_chunk_context = BogusGetChunkContext, \
61 : : [id].get_chunk_space = BogusGetChunkSpace
62 : :
63 : : static const MemoryContextMethods mcxt_methods[] = {
64 : : /* aset.c */
65 : : [MCTX_ASET_ID].alloc = AllocSetAlloc,
66 : : [MCTX_ASET_ID].free_p = AllocSetFree,
67 : : [MCTX_ASET_ID].realloc = AllocSetRealloc,
68 : : [MCTX_ASET_ID].reset = AllocSetReset,
69 : : [MCTX_ASET_ID].delete_context = AllocSetDelete,
70 : : [MCTX_ASET_ID].get_chunk_context = AllocSetGetChunkContext,
71 : : [MCTX_ASET_ID].get_chunk_space = AllocSetGetChunkSpace,
72 : : [MCTX_ASET_ID].is_empty = AllocSetIsEmpty,
73 : : [MCTX_ASET_ID].stats = AllocSetStats,
74 : : #ifdef MEMORY_CONTEXT_CHECKING
75 : : [MCTX_ASET_ID].check = AllocSetCheck,
76 : : #endif
77 : :
78 : : /* generation.c */
79 : : [MCTX_GENERATION_ID].alloc = GenerationAlloc,
80 : : [MCTX_GENERATION_ID].free_p = GenerationFree,
81 : : [MCTX_GENERATION_ID].realloc = GenerationRealloc,
82 : : [MCTX_GENERATION_ID].reset = GenerationReset,
83 : : [MCTX_GENERATION_ID].delete_context = GenerationDelete,
84 : : [MCTX_GENERATION_ID].get_chunk_context = GenerationGetChunkContext,
85 : : [MCTX_GENERATION_ID].get_chunk_space = GenerationGetChunkSpace,
86 : : [MCTX_GENERATION_ID].is_empty = GenerationIsEmpty,
87 : : [MCTX_GENERATION_ID].stats = GenerationStats,
88 : : #ifdef MEMORY_CONTEXT_CHECKING
89 : : [MCTX_GENERATION_ID].check = GenerationCheck,
90 : : #endif
91 : :
92 : : /* slab.c */
93 : : [MCTX_SLAB_ID].alloc = SlabAlloc,
94 : : [MCTX_SLAB_ID].free_p = SlabFree,
95 : : [MCTX_SLAB_ID].realloc = SlabRealloc,
96 : : [MCTX_SLAB_ID].reset = SlabReset,
97 : : [MCTX_SLAB_ID].delete_context = SlabDelete,
98 : : [MCTX_SLAB_ID].get_chunk_context = SlabGetChunkContext,
99 : : [MCTX_SLAB_ID].get_chunk_space = SlabGetChunkSpace,
100 : : [MCTX_SLAB_ID].is_empty = SlabIsEmpty,
101 : : [MCTX_SLAB_ID].stats = SlabStats,
102 : : #ifdef MEMORY_CONTEXT_CHECKING
103 : : [MCTX_SLAB_ID].check = SlabCheck,
104 : : #endif
105 : :
106 : : /* alignedalloc.c */
107 : : [MCTX_ALIGNED_REDIRECT_ID].alloc = NULL, /* not required */
108 : : [MCTX_ALIGNED_REDIRECT_ID].free_p = AlignedAllocFree,
109 : : [MCTX_ALIGNED_REDIRECT_ID].realloc = AlignedAllocRealloc,
110 : : [MCTX_ALIGNED_REDIRECT_ID].reset = NULL, /* not required */
111 : : [MCTX_ALIGNED_REDIRECT_ID].delete_context = NULL, /* not required */
112 : : [MCTX_ALIGNED_REDIRECT_ID].get_chunk_context = AlignedAllocGetChunkContext,
113 : : [MCTX_ALIGNED_REDIRECT_ID].get_chunk_space = AlignedAllocGetChunkSpace,
114 : : [MCTX_ALIGNED_REDIRECT_ID].is_empty = NULL, /* not required */
115 : : [MCTX_ALIGNED_REDIRECT_ID].stats = NULL, /* not required */
116 : : #ifdef MEMORY_CONTEXT_CHECKING
117 : : [MCTX_ALIGNED_REDIRECT_ID].check = NULL, /* not required */
118 : : #endif
119 : :
120 : : /* bump.c */
121 : : [MCTX_BUMP_ID].alloc = BumpAlloc,
122 : : [MCTX_BUMP_ID].free_p = BumpFree,
123 : : [MCTX_BUMP_ID].realloc = BumpRealloc,
124 : : [MCTX_BUMP_ID].reset = BumpReset,
125 : : [MCTX_BUMP_ID].delete_context = BumpDelete,
126 : : [MCTX_BUMP_ID].get_chunk_context = BumpGetChunkContext,
127 : : [MCTX_BUMP_ID].get_chunk_space = BumpGetChunkSpace,
128 : : [MCTX_BUMP_ID].is_empty = BumpIsEmpty,
129 : : [MCTX_BUMP_ID].stats = BumpStats,
130 : : #ifdef MEMORY_CONTEXT_CHECKING
131 : : [MCTX_BUMP_ID].check = BumpCheck,
132 : : #endif
133 : :
134 : :
135 : : /*
136 : : * Reserved and unused IDs should have dummy entries here. This allows us
137 : : * to fail cleanly if a bogus pointer is passed to pfree or the like. It
138 : : * seems sufficient to provide routines for the methods that might get
139 : : * invoked from inspection of a chunk (see MCXT_METHOD calls below).
140 : : */
141 : : BOGUS_MCTX(MCTX_1_RESERVED_GLIBC_ID),
142 : : BOGUS_MCTX(MCTX_2_RESERVED_GLIBC_ID),
143 : : BOGUS_MCTX(MCTX_8_UNUSED_ID),
144 : : BOGUS_MCTX(MCTX_9_UNUSED_ID),
145 : : BOGUS_MCTX(MCTX_10_UNUSED_ID),
146 : : BOGUS_MCTX(MCTX_11_UNUSED_ID),
147 : : BOGUS_MCTX(MCTX_12_UNUSED_ID),
148 : : BOGUS_MCTX(MCTX_13_UNUSED_ID),
149 : : BOGUS_MCTX(MCTX_14_UNUSED_ID),
150 : : BOGUS_MCTX(MCTX_0_RESERVED_UNUSEDMEM_ID),
151 : : BOGUS_MCTX(MCTX_15_RESERVED_WIPEDMEM_ID)
152 : : };
153 : :
154 : : #undef BOGUS_MCTX
155 : :
156 : : /*
157 : : * CurrentMemoryContext
158 : : * Default memory context for allocations.
159 : : */
160 : : MemoryContext CurrentMemoryContext = NULL;
161 : :
162 : : /*
163 : : * Standard top-level contexts. For a description of the purpose of each
164 : : * of these contexts, refer to src/backend/utils/mmgr/README
165 : : */
166 : : MemoryContext TopMemoryContext = NULL;
167 : : MemoryContext ErrorContext = NULL;
168 : : MemoryContext PostmasterContext = NULL;
169 : : MemoryContext CacheMemoryContext = NULL;
170 : : MemoryContext MessageContext = NULL;
171 : : MemoryContext TopTransactionContext = NULL;
172 : : MemoryContext CurTransactionContext = NULL;
173 : :
174 : : /* This is a transient link to the active portal's memory context: */
175 : : MemoryContext PortalContext = NULL;
176 : :
177 : : /* Is memory context logging currently in progress? */
178 : : static bool LogMemoryContextInProgress = false;
179 : :
180 : : static void MemoryContextDeleteOnly(MemoryContext context);
181 : : static void MemoryContextCallResetCallbacks(MemoryContext context);
182 : : static void MemoryContextStatsInternal(MemoryContext context, int level,
183 : : int max_level, int max_children,
184 : : MemoryContextCounters *totals,
185 : : bool print_to_stderr);
186 : : static void MemoryContextStatsPrint(MemoryContext context, void *passthru,
187 : : const char *stats_string,
188 : : bool print_to_stderr);
189 : :
190 : : /*
191 : : * You should not do memory allocations within a critical section, because
192 : : * an out-of-memory error will be escalated to a PANIC. To enforce that
193 : : * rule, the allocation functions Assert that.
194 : : */
195 : : #define AssertNotInCriticalSection(context) \
196 : : Assert(CritSectionCount == 0 || (context)->allowInCritSection)
197 : :
198 : : /*
199 : : * Call the given function in the MemoryContextMethods for the memory context
200 : : * type that 'pointer' belongs to.
201 : : */
202 : : #define MCXT_METHOD(pointer, method) \
203 : : mcxt_methods[GetMemoryChunkMethodID(pointer)].method
204 : :
205 : : /*
206 : : * GetMemoryChunkMethodID
207 : : * Return the MemoryContextMethodID from the uint64 chunk header which
208 : : * directly precedes 'pointer'.
209 : : */
210 : : static inline MemoryContextMethodID
211 : 56160276 : GetMemoryChunkMethodID(const void *pointer)
212 : : {
213 : 56160276 : uint64 header;
214 : :
215 : : /*
216 : : * Try to detect bogus pointers handed to us, poorly though we can.
217 : : * Presumably, a pointer that isn't MAXALIGNED isn't pointing at an
218 : : * allocated chunk.
219 : : */
220 [ + - ]: 56160276 : Assert(pointer == (const void *) MAXALIGN(pointer));
221 : :
222 : : /* Allow access to the uint64 header */
223 : 56160276 : VALGRIND_MAKE_MEM_DEFINED((char *) pointer - sizeof(uint64), sizeof(uint64));
224 : :
225 : 56160276 : header = *((const uint64 *) ((const char *) pointer - sizeof(uint64)));
226 : :
227 : : /* Disallow access to the uint64 header */
228 : 56160276 : VALGRIND_MAKE_MEM_NOACCESS((char *) pointer - sizeof(uint64), sizeof(uint64));
229 : :
230 : 112320552 : return (MemoryContextMethodID) (header & MEMORY_CONTEXT_METHODID_MASK);
231 : 56160276 : }
232 : :
233 : : /*
234 : : * GetMemoryChunkHeader
235 : : * Return the uint64 chunk header which directly precedes 'pointer'.
236 : : *
237 : : * This is only used after GetMemoryChunkMethodID, so no need for error checks.
238 : : */
239 : : static inline uint64
240 : 0 : GetMemoryChunkHeader(const void *pointer)
241 : : {
242 : 0 : uint64 header;
243 : :
244 : : /* Allow access to the uint64 header */
245 : 0 : VALGRIND_MAKE_MEM_DEFINED((char *) pointer - sizeof(uint64), sizeof(uint64));
246 : :
247 : 0 : header = *((const uint64 *) ((const char *) pointer - sizeof(uint64)));
248 : :
249 : : /* Disallow access to the uint64 header */
250 : 0 : VALGRIND_MAKE_MEM_NOACCESS((char *) pointer - sizeof(uint64), sizeof(uint64));
251 : :
252 : 0 : return header;
253 : 0 : }
254 : :
255 : : /*
256 : : * MemoryContextTraverseNext
257 : : * Helper function to traverse all descendants of a memory context
258 : : * without recursion.
259 : : *
260 : : * Recursion could lead to out-of-stack errors with deep context hierarchies,
261 : : * which would be unpleasant in error cleanup code paths.
262 : : *
263 : : * To process 'context' and all its descendants, use a loop like this:
264 : : *
265 : : * <process 'context'>
266 : : * for (MemoryContext curr = context->firstchild;
267 : : * curr != NULL;
268 : : * curr = MemoryContextTraverseNext(curr, context))
269 : : * {
270 : : * <process 'curr'>
271 : : * }
272 : : *
273 : : * This visits all the contexts in pre-order, that is a node is visited
274 : : * before its children.
275 : : */
276 : : static MemoryContext
277 : 11819614 : MemoryContextTraverseNext(MemoryContext curr, MemoryContext top)
278 : : {
279 : : /* After processing a node, traverse to its first child if any */
280 [ + + ]: 11819614 : if (curr->firstchild != NULL)
281 : 1244709 : return curr->firstchild;
282 : :
283 : : /*
284 : : * After processing a childless node, traverse to its next sibling if
285 : : * there is one. If there isn't, traverse back up to the parent (which
286 : : * has already been visited, and now so have all its descendants). We're
287 : : * done if that is "top", otherwise traverse to its next sibling if any,
288 : : * otherwise repeat moving up.
289 : : */
290 [ + + ]: 11819614 : while (curr->nextchild == NULL)
291 : : {
292 : 1370292 : curr = curr->parent;
293 [ + + ]: 1370292 : if (curr == top)
294 : 125583 : return NULL;
295 : : }
296 : 10449322 : return curr->nextchild;
297 : 11819614 : }
298 : :
299 : : /*
300 : : * Support routines to trap use of invalid memory context method IDs
301 : : * (from calling pfree or the like on a bogus pointer). As a possible
302 : : * aid in debugging, we report the header word along with the pointer
303 : : * address (if we got here, there must be an accessible header word).
304 : : */
305 : : static void
306 : 0 : BogusFree(void *pointer)
307 : : {
308 [ # # # # ]: 0 : elog(ERROR, "pfree called with invalid pointer %p (header 0x%016" PRIx64 ")",
309 : : pointer, GetMemoryChunkHeader(pointer));
310 : 0 : }
311 : :
312 : : static void *
313 : 0 : BogusRealloc(void *pointer, Size size, int flags)
314 : : {
315 [ # # # # ]: 0 : elog(ERROR, "repalloc called with invalid pointer %p (header 0x%016" PRIx64 ")",
316 : : pointer, GetMemoryChunkHeader(pointer));
317 : 0 : return NULL; /* keep compiler quiet */
318 : : }
319 : :
320 : : static MemoryContext
321 : 0 : BogusGetChunkContext(void *pointer)
322 : : {
323 [ # # # # ]: 0 : elog(ERROR, "GetMemoryChunkContext called with invalid pointer %p (header 0x%016" PRIx64 ")",
324 : : pointer, GetMemoryChunkHeader(pointer));
325 : 0 : return NULL; /* keep compiler quiet */
326 : : }
327 : :
328 : : static Size
329 : 0 : BogusGetChunkSpace(void *pointer)
330 : : {
331 [ # # # # ]: 0 : elog(ERROR, "GetMemoryChunkSpace called with invalid pointer %p (header 0x%016" PRIx64 ")",
332 : : pointer, GetMemoryChunkHeader(pointer));
333 : 0 : return 0; /* keep compiler quiet */
334 : : }
335 : :
336 : :
337 : : /*****************************************************************************
338 : : * EXPORTED ROUTINES *
339 : : *****************************************************************************/
340 : :
341 : :
342 : : /*
343 : : * MemoryContextInit
344 : : * Start up the memory-context subsystem.
345 : : *
346 : : * This must be called before creating contexts or allocating memory in
347 : : * contexts. TopMemoryContext and ErrorContext are initialized here;
348 : : * other contexts must be created afterwards.
349 : : *
350 : : * In normal multi-backend operation, this is called once during
351 : : * postmaster startup, and not at all by individual backend startup
352 : : * (since the backends inherit an already-initialized context subsystem
353 : : * by virtue of being forked off the postmaster). But in an EXEC_BACKEND
354 : : * build, each process must do this for itself.
355 : : *
356 : : * In a standalone backend this must be called during backend startup.
357 : : */
358 : : void
359 : 8 : MemoryContextInit(void)
360 : : {
361 [ + - ]: 8 : Assert(TopMemoryContext == NULL);
362 : :
363 : : /*
364 : : * First, initialize TopMemoryContext, which is the parent of all others.
365 : : */
366 : 8 : TopMemoryContext = AllocSetContextCreate((MemoryContext) NULL,
367 : : "TopMemoryContext",
368 : : ALLOCSET_DEFAULT_SIZES);
369 : :
370 : : /*
371 : : * Not having any other place to point CurrentMemoryContext, make it point
372 : : * to TopMemoryContext. Caller should change this soon!
373 : : */
374 : 8 : CurrentMemoryContext = TopMemoryContext;
375 : :
376 : : /*
377 : : * Initialize ErrorContext as an AllocSetContext with slow growth rate ---
378 : : * we don't really expect much to be allocated in it. More to the point,
379 : : * require it to contain at least 8K at all times. This is the only case
380 : : * where retained memory in a context is *essential* --- we want to be
381 : : * sure ErrorContext still has some memory even if we've run out
382 : : * elsewhere! Also, allow allocations in ErrorContext within a critical
383 : : * section. Otherwise a PANIC will cause an assertion failure in the error
384 : : * reporting code, before printing out the real cause of the failure.
385 : : *
386 : : * This should be the last step in this function, as elog.c assumes memory
387 : : * management works once ErrorContext is non-null.
388 : : */
389 : 8 : ErrorContext = AllocSetContextCreate(TopMemoryContext,
390 : : "ErrorContext",
391 : : 8 * 1024,
392 : : 8 * 1024,
393 : : 8 * 1024);
394 : 8 : MemoryContextAllowInCriticalSection(ErrorContext, true);
395 : 8 : }
396 : :
397 : : /*
398 : : * MemoryContextReset
399 : : * Release all space allocated within a context and delete all its
400 : : * descendant contexts (but not the named context itself).
401 : : */
402 : : void
403 : 43125499 : MemoryContextReset(MemoryContext context)
404 : : {
405 [ + - + + : 43125499 : Assert(MemoryContextIsValid(context));
+ - + + ]
406 : :
407 : : /* save a function call in common case where there are no children */
408 [ + + ]: 43125499 : if (context->firstchild != NULL)
409 : 50838 : MemoryContextDeleteChildren(context);
410 : :
411 : : /* save a function call if no pallocs since startup or last reset */
412 [ + + ]: 43125499 : if (!context->isReset)
413 : 4543891 : MemoryContextResetOnly(context);
414 : 43125499 : }
415 : :
416 : : /*
417 : : * MemoryContextResetOnly
418 : : * Release all space allocated within a context.
419 : : * Nothing is done to the context's descendant contexts.
420 : : */
421 : : void
422 : 5843800 : MemoryContextResetOnly(MemoryContext context)
423 : : {
424 [ + - + + : 5843800 : Assert(MemoryContextIsValid(context));
+ - + + ]
425 : :
426 : : /* Nothing to do if no pallocs since startup or last reset */
427 [ + + ]: 5843800 : if (!context->isReset)
428 : : {
429 : 5843604 : MemoryContextCallResetCallbacks(context);
430 : :
431 : : /*
432 : : * If context->ident points into the context's memory, it will become
433 : : * a dangling pointer. We could prevent that by setting it to NULL
434 : : * here, but that would break valid coding patterns that keep the
435 : : * ident elsewhere, e.g. in a parent context. So for now we assume
436 : : * the programmer got it right.
437 : : */
438 : :
439 : 5843604 : context->methods->reset(context);
440 : 5843604 : context->isReset = true;
441 : 5843604 : }
442 : 5843800 : }
443 : :
444 : : /*
445 : : * MemoryContextResetChildren
446 : : * Release all space allocated within a context's descendants,
447 : : * but don't delete the contexts themselves. The named context
448 : : * itself is not touched.
449 : : */
450 : : void
451 : 0 : MemoryContextResetChildren(MemoryContext context)
452 : : {
453 [ # # # # : 0 : Assert(MemoryContextIsValid(context));
# # # # ]
454 : :
455 [ # # ]: 0 : for (MemoryContext curr = context->firstchild;
456 : 0 : curr != NULL;
457 : 0 : curr = MemoryContextTraverseNext(curr, context))
458 : : {
459 : 0 : MemoryContextResetOnly(curr);
460 : 0 : }
461 : 0 : }
462 : :
463 : : /*
464 : : * MemoryContextDelete
465 : : * Delete a context and its descendants, and release all space
466 : : * allocated therein.
467 : : *
468 : : * The type-specific delete routine removes all storage for the context,
469 : : * but we have to deal with descendant nodes here.
470 : : */
471 : : void
472 : 2480584 : MemoryContextDelete(MemoryContext context)
473 : : {
474 : 2480584 : MemoryContext curr;
475 : :
476 [ + - + + : 2480584 : Assert(MemoryContextIsValid(context));
+ + + + ]
477 : :
478 : : /*
479 : : * Delete subcontexts from the bottom up.
480 : : *
481 : : * Note: Do not use recursion here. A "stack depth limit exceeded" error
482 : : * would be unpleasant if we're already in the process of cleaning up from
483 : : * transaction abort. We also cannot use MemoryContextTraverseNext() here
484 : : * because we modify the tree as we go.
485 : : */
486 : 2480584 : curr = context;
487 : 2961933 : for (;;)
488 : : {
489 : 2961933 : MemoryContext parent;
490 : :
491 : : /* Descend down until we find a leaf context with no children */
492 [ + + ]: 3443282 : while (curr->firstchild != NULL)
493 : 481349 : curr = curr->firstchild;
494 : :
495 : : /*
496 : : * We're now at a leaf with no children. Free it and continue from the
497 : : * parent. Or if this was the original node, we're all done.
498 : : */
499 : 2961933 : parent = curr->parent;
500 : 2961933 : MemoryContextDeleteOnly(curr);
501 : :
502 [ + + ]: 2961933 : if (curr == context)
503 : 2480584 : break;
504 : 481349 : curr = parent;
505 [ - + + ]: 2961933 : }
506 : 2480584 : }
507 : :
508 : : /*
509 : : * Subroutine of MemoryContextDelete,
510 : : * to delete a context that has no children.
511 : : * We must also delink the context from its parent, if it has one.
512 : : */
513 : : static void
514 : 2961933 : MemoryContextDeleteOnly(MemoryContext context)
515 : : {
516 [ + - + + : 2961933 : Assert(MemoryContextIsValid(context));
+ + + + ]
517 : : /* We had better not be deleting TopMemoryContext ... */
518 [ + - ]: 2961933 : Assert(context != TopMemoryContext);
519 : : /* And not CurrentMemoryContext, either */
520 [ + - ]: 2961933 : Assert(context != CurrentMemoryContext);
521 : : /* All the children should've been deleted already */
522 [ + - ]: 2961933 : Assert(context->firstchild == NULL);
523 : :
524 : : /*
525 : : * It's not entirely clear whether 'tis better to do this before or after
526 : : * delinking the context; but an error in a callback will likely result in
527 : : * leaking the whole context (if it's not a root context) if we do it
528 : : * after, so let's do it before.
529 : : */
530 : 2961933 : MemoryContextCallResetCallbacks(context);
531 : :
532 : : /*
533 : : * We delink the context from its parent before deleting it, so that if
534 : : * there's an error we won't have deleted/busted contexts still attached
535 : : * to the context tree. Better a leak than a crash.
536 : : */
537 : 2961933 : MemoryContextSetParent(context, NULL);
538 : :
539 : : /*
540 : : * Also reset the context's ident pointer, in case it points into the
541 : : * context. This would only matter if someone tries to get stats on the
542 : : * (already unlinked) context, which is unlikely, but let's be safe.
543 : : */
544 : 2961933 : context->ident = NULL;
545 : :
546 : 2961933 : context->methods->delete_context(context);
547 : 2961933 : }
548 : :
549 : : /*
550 : : * MemoryContextDeleteChildren
551 : : * Delete all the descendants of the named context and release all
552 : : * space allocated therein. The named context itself is not touched.
553 : : */
554 : : void
555 : 83776 : MemoryContextDeleteChildren(MemoryContext context)
556 : : {
557 [ + - + + : 83776 : Assert(MemoryContextIsValid(context));
+ - + - ]
558 : :
559 : : /*
560 : : * MemoryContextDelete will delink the child from me, so just iterate as
561 : : * long as there is a child.
562 : : */
563 [ + + ]: 143496 : while (context->firstchild != NULL)
564 : 59720 : MemoryContextDelete(context->firstchild);
565 : 83776 : }
566 : :
567 : : /*
568 : : * MemoryContextRegisterResetCallback
569 : : * Register a function to be called before next context reset/delete.
570 : : * Such callbacks will be called in reverse order of registration.
571 : : *
572 : : * The caller is responsible for allocating a MemoryContextCallback struct
573 : : * to hold the info about this callback request, and for filling in the
574 : : * "func" and "arg" fields in the struct to show what function to call with
575 : : * what argument. Typically the callback struct should be allocated within
576 : : * the specified context, since that means it will automatically be freed
577 : : * when no longer needed.
578 : : *
579 : : * Note that callers can assume this cannot fail.
580 : : */
581 : : void
582 : 10285 : MemoryContextRegisterResetCallback(MemoryContext context,
583 : : MemoryContextCallback *cb)
584 : : {
585 [ + - - + : 10285 : Assert(MemoryContextIsValid(context));
# # # # ]
586 : :
587 : : /* Push onto head so this will be called before older registrants. */
588 : 10285 : cb->next = context->reset_cbs;
589 : 10285 : context->reset_cbs = cb;
590 : : /* Mark the context as non-reset (it probably is already). */
591 : 10285 : context->isReset = false;
592 : 10285 : }
593 : :
594 : : /*
595 : : * MemoryContextUnregisterResetCallback
596 : : * Undo the effects of MemoryContextRegisterResetCallback.
597 : : *
598 : : * This can be used if a callback's effects are no longer required
599 : : * at some point before the context has been reset/deleted. It is the
600 : : * caller's responsibility to pfree the callback struct (if needed).
601 : : *
602 : : * An assertion failure occurs if the callback was not registered.
603 : : * We could alternatively define that case as a no-op, but that seems too
604 : : * likely to mask programming errors such as passing the wrong context.
605 : : */
606 : : void
607 : 0 : MemoryContextUnregisterResetCallback(MemoryContext context,
608 : : MemoryContextCallback *cb)
609 : : {
610 : 0 : MemoryContextCallback *prev,
611 : : *cur;
612 : :
613 [ # # # # : 0 : Assert(MemoryContextIsValid(context));
# # # # ]
614 : :
615 [ # # ]: 0 : for (prev = NULL, cur = context->reset_cbs; cur != NULL;
616 : 0 : prev = cur, cur = cur->next)
617 : : {
618 [ # # ]: 0 : if (cur != cb)
619 : 0 : continue;
620 [ # # ]: 0 : if (prev)
621 : 0 : prev->next = cur->next;
622 : : else
623 : 0 : context->reset_cbs = cur->next;
624 : 0 : return;
625 : : }
626 : 0 : Assert(false);
627 [ # # ]: 0 : }
628 : :
629 : : /*
630 : : * MemoryContextCallResetCallbacks
631 : : * Internal function to call all registered callbacks for context.
632 : : */
633 : : static void
634 : 8805537 : MemoryContextCallResetCallbacks(MemoryContext context)
635 : : {
636 : 8805537 : MemoryContextCallback *cb;
637 : :
638 : : /*
639 : : * We pop each callback from the list before calling. That way, if an
640 : : * error occurs inside the callback, we won't try to call it a second time
641 : : * in the likely event that we reset or delete the context later.
642 : : */
643 [ + + ]: 8815822 : while ((cb = context->reset_cbs) != NULL)
644 : : {
645 : 10285 : context->reset_cbs = cb->next;
646 : 10285 : cb->func(cb->arg);
647 : : }
648 : 8805537 : }
649 : :
650 : : /*
651 : : * MemoryContextSetIdentifier
652 : : * Set the identifier string for a memory context.
653 : : *
654 : : * An identifier can be provided to help distinguish among different contexts
655 : : * of the same kind in memory context stats dumps. The identifier string
656 : : * must live at least as long as the context it is for; typically it is
657 : : * allocated inside that context, so that it automatically goes away on
658 : : * context deletion. Pass id = NULL to forget any old identifier.
659 : : */
660 : : void
661 : 215721 : MemoryContextSetIdentifier(MemoryContext context, const char *id)
662 : : {
663 [ + - - + : 215721 : Assert(MemoryContextIsValid(context));
# # # # ]
664 : 215721 : context->ident = id;
665 : 215721 : }
666 : :
667 : : /*
668 : : * MemoryContextSetParent
669 : : * Change a context to belong to a new parent (or no parent).
670 : : *
671 : : * We provide this as an API function because it is sometimes useful to
672 : : * change a context's lifespan after creation. For example, a context
673 : : * might be created underneath a transient context, filled with data,
674 : : * and then reparented underneath CacheMemoryContext to make it long-lived.
675 : : * In this way no special effort is needed to get rid of the context in case
676 : : * a failure occurs before its contents are completely set up.
677 : : *
678 : : * Callers often assume that this function cannot fail, so don't put any
679 : : * elog(ERROR) calls in it.
680 : : *
681 : : * A possible caller error is to reparent a context under itself, creating
682 : : * a loop in the context graph. We assert here that context != new_parent,
683 : : * but checking for multi-level loops seems more trouble than it's worth.
684 : : */
685 : : void
686 : 2990109 : MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
687 : : {
688 [ + - + + : 2990109 : Assert(MemoryContextIsValid(context));
+ + + + ]
689 [ + - ]: 2990109 : Assert(context != new_parent);
690 : :
691 : : /* Fast path if it's got correct parent already */
692 [ + + ]: 2990109 : if (new_parent == context->parent)
693 : 1570 : return;
694 : :
695 : : /* Delink from existing parent, if any */
696 [ - + ]: 2988539 : if (context->parent)
697 : : {
698 : 2988539 : MemoryContext parent = context->parent;
699 : :
700 [ + + ]: 2988539 : if (context->prevchild != NULL)
701 : 109384 : context->prevchild->nextchild = context->nextchild;
702 : : else
703 : : {
704 [ + - ]: 2879155 : Assert(parent->firstchild == context);
705 : 2879155 : parent->firstchild = context->nextchild;
706 : : }
707 : :
708 [ + + ]: 2988539 : if (context->nextchild != NULL)
709 : 1338537 : context->nextchild->prevchild = context->prevchild;
710 : 2988539 : }
711 : :
712 : : /* And relink */
713 [ + + ]: 2988539 : if (new_parent)
714 : : {
715 [ + - - + : 26606 : Assert(MemoryContextIsValid(new_parent));
# # # # ]
716 : 26606 : context->parent = new_parent;
717 : 26606 : context->prevchild = NULL;
718 : 26606 : context->nextchild = new_parent->firstchild;
719 [ + + ]: 26606 : if (new_parent->firstchild != NULL)
720 : 24699 : new_parent->firstchild->prevchild = context;
721 : 26606 : new_parent->firstchild = context;
722 : 26606 : }
723 : : else
724 : : {
725 : 2961933 : context->parent = NULL;
726 : 2961933 : context->prevchild = NULL;
727 : 2961933 : context->nextchild = NULL;
728 : : }
729 : 2990109 : }
730 : :
731 : : /*
732 : : * MemoryContextAllowInCriticalSection
733 : : * Allow/disallow allocations in this memory context within a critical
734 : : * section.
735 : : *
736 : : * Normally, memory allocations are not allowed within a critical section,
737 : : * because a failure would lead to PANIC. There are a few exceptions to
738 : : * that, like allocations related to debugging code that is not supposed to
739 : : * be enabled in production. This function can be used to exempt specific
740 : : * memory contexts from the assertion in palloc().
741 : : */
742 : : void
743 : 11 : MemoryContextAllowInCriticalSection(MemoryContext context, bool allow)
744 : : {
745 [ + - - + : 11 : Assert(MemoryContextIsValid(context));
# # # # ]
746 : :
747 : 11 : context->allowInCritSection = allow;
748 : 11 : }
749 : :
750 : : /*
751 : : * GetMemoryChunkContext
752 : : * Given a currently-allocated chunk, determine the MemoryContext that
753 : : * the chunk belongs to.
754 : : */
755 : : MemoryContext
756 : 526620 : GetMemoryChunkContext(void *pointer)
757 : : {
758 : 526620 : return MCXT_METHOD(pointer, get_chunk_context) (pointer);
759 : : }
760 : :
761 : : /*
762 : : * GetMemoryChunkSpace
763 : : * Given a currently-allocated chunk, determine the total space
764 : : * it occupies (including all memory-allocation overhead).
765 : : *
766 : : * This is useful for measuring the total space occupied by a set of
767 : : * allocated chunks.
768 : : */
769 : : Size
770 : 4408291 : GetMemoryChunkSpace(void *pointer)
771 : : {
772 : 4408291 : return MCXT_METHOD(pointer, get_chunk_space) (pointer);
773 : : }
774 : :
775 : : /*
776 : : * MemoryContextGetParent
777 : : * Get the parent context (if any) of the specified context
778 : : */
779 : : MemoryContext
780 : 2794 : MemoryContextGetParent(MemoryContext context)
781 : : {
782 [ + - - + : 2794 : Assert(MemoryContextIsValid(context));
# # # # ]
783 : :
784 : 2794 : return context->parent;
785 : : }
786 : :
787 : : /*
788 : : * MemoryContextIsEmpty
789 : : * Is a memory context empty of any allocated space?
790 : : */
791 : : bool
792 : 482 : MemoryContextIsEmpty(MemoryContext context)
793 : : {
794 [ + - - + : 482 : Assert(MemoryContextIsValid(context));
# # # # ]
795 : :
796 : : /*
797 : : * For now, we consider a memory context nonempty if it has any children;
798 : : * perhaps this should be changed later.
799 : : */
800 [ - + ]: 482 : if (context->firstchild != NULL)
801 : 0 : return false;
802 : : /* Otherwise use the type-specific inquiry */
803 : 482 : return context->methods->is_empty(context);
804 : 482 : }
805 : :
806 : : /*
807 : : * Find the memory allocated to blocks for this memory context. If recurse is
808 : : * true, also include children.
809 : : */
810 : : Size
811 : 214392 : MemoryContextMemAllocated(MemoryContext context, bool recurse)
812 : : {
813 : 214392 : Size total = context->mem_allocated;
814 : :
815 [ + - + + : 214392 : Assert(MemoryContextIsValid(context));
+ - + - ]
816 : :
817 [ + - ]: 214392 : if (recurse)
818 : : {
819 [ + + ]: 350566 : for (MemoryContext curr = context->firstchild;
820 : 350566 : curr != NULL;
821 : 136174 : curr = MemoryContextTraverseNext(curr, context))
822 : : {
823 : 136174 : total += curr->mem_allocated;
824 : 136174 : }
825 : 214392 : }
826 : :
827 : 428784 : return total;
828 : 214392 : }
829 : :
830 : : /*
831 : : * Return the memory consumption statistics about the given context and its
832 : : * children.
833 : : */
834 : : void
835 : 5 : MemoryContextMemConsumed(MemoryContext context,
836 : : MemoryContextCounters *consumed)
837 : : {
838 [ + - - + : 5 : Assert(MemoryContextIsValid(context));
# # # # ]
839 : :
840 : 5 : memset(consumed, 0, sizeof(*consumed));
841 : :
842 : : /* Examine the context itself */
843 : 5 : context->methods->stats(context, NULL, NULL, consumed, false);
844 : :
845 : : /* Examine children, using iteration not recursion */
846 [ + - ]: 5 : for (MemoryContext curr = context->firstchild;
847 : 5 : curr != NULL;
848 : 0 : curr = MemoryContextTraverseNext(curr, context))
849 : : {
850 : 0 : curr->methods->stats(curr, NULL, NULL, consumed, false);
851 : 0 : }
852 : 5 : }
853 : :
854 : : /*
855 : : * MemoryContextStats
856 : : * Print statistics about the named context and all its descendants.
857 : : *
858 : : * This is just a debugging utility, so it's not very fancy. However, we do
859 : : * make some effort to summarize when the output would otherwise be very long.
860 : : * The statistics are sent to stderr.
861 : : */
862 : : void
863 : 0 : MemoryContextStats(MemoryContext context)
864 : : {
865 : : /* Hard-wired limits are usually good enough */
866 : 0 : MemoryContextStatsDetail(context, 100, 100, true);
867 : 0 : }
868 : :
869 : : /*
870 : : * MemoryContextStatsDetail
871 : : *
872 : : * Entry point for use if you want to vary the number of child contexts shown.
873 : : *
874 : : * If print_to_stderr is true, print statistics about the memory contexts
875 : : * with fprintf(stderr), otherwise use ereport().
876 : : */
877 : : void
878 : 2 : MemoryContextStatsDetail(MemoryContext context,
879 : : int max_level, int max_children,
880 : : bool print_to_stderr)
881 : : {
882 : 2 : MemoryContextCounters grand_totals;
883 : :
884 : 2 : memset(&grand_totals, 0, sizeof(grand_totals));
885 : :
886 : 4 : MemoryContextStatsInternal(context, 1, max_level, max_children,
887 : 2 : &grand_totals, print_to_stderr);
888 : :
889 [ - + ]: 2 : if (print_to_stderr)
890 : 0 : fprintf(stderr,
891 : : "Grand total: %zu bytes in %zu blocks; %zu free (%zu chunks); %zu used\n",
892 : 0 : grand_totals.totalspace, grand_totals.nblocks,
893 : 0 : grand_totals.freespace, grand_totals.freechunks,
894 : 0 : grand_totals.totalspace - grand_totals.freespace);
895 : : else
896 : : {
897 : : /*
898 : : * Use LOG_SERVER_ONLY to prevent the memory contexts from being sent
899 : : * to the connected client.
900 : : *
901 : : * We don't buffer the information about all memory contexts in a
902 : : * backend into StringInfo and log it as one message. That would
903 : : * require the buffer to be enlarged, risking an OOM as there could be
904 : : * a large number of memory contexts in a backend. Instead, we log
905 : : * one message per memory context.
906 : : */
907 [ - + + - ]: 2 : ereport(LOG_SERVER_ONLY,
908 : : (errhidestmt(true),
909 : : errhidecontext(true),
910 : : errmsg_internal("Grand total: %zu bytes in %zu blocks; %zu free (%zu chunks); %zu used",
911 : : grand_totals.totalspace, grand_totals.nblocks,
912 : : grand_totals.freespace, grand_totals.freechunks,
913 : : grand_totals.totalspace - grand_totals.freespace)));
914 : : }
915 : 2 : }
916 : :
917 : : /*
918 : : * MemoryContextStatsInternal
919 : : * One recursion level for MemoryContextStats
920 : : *
921 : : * Print stats for this context if possible, but in any case accumulate counts
922 : : * into *totals (if not NULL).
923 : : */
924 : : static void
925 : 258 : MemoryContextStatsInternal(MemoryContext context, int level,
926 : : int max_level, int max_children,
927 : : MemoryContextCounters *totals,
928 : : bool print_to_stderr)
929 : : {
930 : 258 : MemoryContext child;
931 : 258 : int ichild;
932 : :
933 [ + - - + : 258 : Assert(MemoryContextIsValid(context));
# # # # ]
934 : :
935 : : /* Examine the context itself */
936 : 516 : context->methods->stats(context,
937 : : MemoryContextStatsPrint,
938 : : &level,
939 : 258 : totals, print_to_stderr);
940 : :
941 : : /*
942 : : * Examine children.
943 : : *
944 : : * If we are past the recursion depth limit or already running low on
945 : : * stack, do not print them explicitly but just summarize them. Similarly,
946 : : * if there are more than max_children of them, we do not print the rest
947 : : * explicitly, but just summarize them.
948 : : */
949 : 258 : child = context->firstchild;
950 : 258 : ichild = 0;
951 [ + - - + ]: 258 : if (level <= max_level && !stack_is_too_deep())
952 : : {
953 [ + + + + ]: 514 : for (; child != NULL && ichild < max_children;
954 : 256 : child = child->nextchild, ichild++)
955 : : {
956 : 512 : MemoryContextStatsInternal(child, level + 1,
957 : 256 : max_level, max_children,
958 : 256 : totals,
959 : 256 : print_to_stderr);
960 : 256 : }
961 : 258 : }
962 : :
963 [ + - ]: 258 : if (child != NULL)
964 : : {
965 : : /* Summarize the rest of the children, avoiding recursion. */
966 : 0 : MemoryContextCounters local_totals;
967 : :
968 : 0 : memset(&local_totals, 0, sizeof(local_totals));
969 : :
970 : 0 : ichild = 0;
971 [ # # ]: 0 : while (child != NULL)
972 : : {
973 : 0 : child->methods->stats(child, NULL, NULL, &local_totals, false);
974 : 0 : ichild++;
975 : 0 : child = MemoryContextTraverseNext(child, context);
976 : : }
977 : :
978 [ # # ]: 0 : if (print_to_stderr)
979 : : {
980 [ # # ]: 0 : for (int i = 0; i < level; i++)
981 : 0 : fprintf(stderr, " ");
982 : 0 : fprintf(stderr,
983 : : "%d more child contexts containing %zu total in %zu blocks; %zu free (%zu chunks); %zu used\n",
984 : 0 : ichild,
985 : 0 : local_totals.totalspace,
986 : 0 : local_totals.nblocks,
987 : 0 : local_totals.freespace,
988 : 0 : local_totals.freechunks,
989 : 0 : local_totals.totalspace - local_totals.freespace);
990 : 0 : }
991 : : else
992 [ # # # # ]: 0 : ereport(LOG_SERVER_ONLY,
993 : : (errhidestmt(true),
994 : : errhidecontext(true),
995 : : errmsg_internal("level: %d; %d more child contexts containing %zu total in %zu blocks; %zu free (%zu chunks); %zu used",
996 : : level,
997 : : ichild,
998 : : local_totals.totalspace,
999 : : local_totals.nblocks,
1000 : : local_totals.freespace,
1001 : : local_totals.freechunks,
1002 : : local_totals.totalspace - local_totals.freespace)));
1003 : :
1004 [ # # ]: 0 : if (totals)
1005 : : {
1006 : 0 : totals->nblocks += local_totals.nblocks;
1007 : 0 : totals->freechunks += local_totals.freechunks;
1008 : 0 : totals->totalspace += local_totals.totalspace;
1009 : 0 : totals->freespace += local_totals.freespace;
1010 : 0 : }
1011 : 0 : }
1012 : 258 : }
1013 : :
1014 : : /*
1015 : : * MemoryContextStatsPrint
1016 : : * Print callback used by MemoryContextStatsInternal
1017 : : *
1018 : : * For now, the passthru pointer just points to "int level"; later we might
1019 : : * make that more complicated.
1020 : : */
1021 : : static void
1022 : 258 : MemoryContextStatsPrint(MemoryContext context, void *passthru,
1023 : : const char *stats_string,
1024 : : bool print_to_stderr)
1025 : : {
1026 : 258 : int level = *(int *) passthru;
1027 : 258 : const char *name = context->name;
1028 : 258 : const char *ident = context->ident;
1029 : 258 : char truncated_ident[110];
1030 : 258 : int i;
1031 : :
1032 : : /*
1033 : : * It seems preferable to label dynahash contexts with just the hash table
1034 : : * name. Those are already unique enough, so the "dynahash" part isn't
1035 : : * very helpful, and this way is more consistent with pre-v11 practice.
1036 : : */
1037 [ + + + + ]: 258 : if (ident && strcmp(name, "dynahash") == 0)
1038 : : {
1039 : 30 : name = ident;
1040 : 30 : ident = NULL;
1041 : 30 : }
1042 : :
1043 : 258 : truncated_ident[0] = '\0';
1044 : :
1045 [ + + ]: 258 : if (ident)
1046 : : {
1047 : : /*
1048 : : * Some contexts may have very long identifiers (e.g., SQL queries).
1049 : : * Arbitrarily truncate at 100 bytes, but be careful not to break
1050 : : * multibyte characters. Also, replace ASCII control characters, such
1051 : : * as newlines, with spaces.
1052 : : */
1053 : 190 : int idlen = strlen(ident);
1054 : 190 : bool truncated = false;
1055 : :
1056 : 190 : strcpy(truncated_ident, ": ");
1057 : 190 : i = strlen(truncated_ident);
1058 : :
1059 [ + - ]: 190 : if (idlen > 100)
1060 : : {
1061 : 0 : idlen = pg_mbcliplen(ident, idlen, 100);
1062 : 0 : truncated = true;
1063 : 0 : }
1064 : :
1065 [ + + ]: 5311 : while (idlen-- > 0)
1066 : : {
1067 : 5121 : unsigned char c = *ident++;
1068 : :
1069 [ + - ]: 5121 : if (c < ' ')
1070 : 0 : c = ' ';
1071 : 5121 : truncated_ident[i++] = c;
1072 : 5121 : }
1073 : 190 : truncated_ident[i] = '\0';
1074 : :
1075 [ + - ]: 190 : if (truncated)
1076 : 0 : strcat(truncated_ident, "...");
1077 : 190 : }
1078 : :
1079 [ - + ]: 258 : if (print_to_stderr)
1080 : : {
1081 [ # # ]: 0 : for (i = 1; i < level; i++)
1082 : 0 : fprintf(stderr, " ");
1083 : 0 : fprintf(stderr, "%s: %s%s\n", name, stats_string, truncated_ident);
1084 : 0 : }
1085 : : else
1086 [ - + + - ]: 258 : ereport(LOG_SERVER_ONLY,
1087 : : (errhidestmt(true),
1088 : : errhidecontext(true),
1089 : : errmsg_internal("level: %d; %s: %s%s",
1090 : : level, name, stats_string, truncated_ident)));
1091 : 258 : }
1092 : :
1093 : : /*
1094 : : * MemoryContextCheck
1095 : : * Check all chunks in the named context and its children.
1096 : : *
1097 : : * This is just a debugging utility, so it's not fancy.
1098 : : */
1099 : : #ifdef MEMORY_CONTEXT_CHECKING
1100 : : void
1101 : 52263 : MemoryContextCheck(MemoryContext context)
1102 : : {
1103 [ + - - + : 52263 : Assert(MemoryContextIsValid(context));
# # # # ]
1104 : 52263 : context->methods->check(context);
1105 : :
1106 [ + + ]: 11735703 : for (MemoryContext curr = context->firstchild;
1107 : 11735703 : curr != NULL;
1108 : 11683440 : curr = MemoryContextTraverseNext(curr, context))
1109 : : {
1110 [ + - + + : 11683440 : Assert(MemoryContextIsValid(curr));
+ - + + ]
1111 : 11683440 : curr->methods->check(curr);
1112 : 11683440 : }
1113 : 52263 : }
1114 : : #endif
1115 : :
1116 : : /*
1117 : : * MemoryContextCreate
1118 : : * Context-type-independent part of context creation.
1119 : : *
1120 : : * This is only intended to be called by context-type-specific
1121 : : * context creation routines, not by the unwashed masses.
1122 : : *
1123 : : * The memory context creation procedure goes like this:
1124 : : * 1. Context-type-specific routine makes some initial space allocation,
1125 : : * including enough space for the context header. If it fails,
1126 : : * it can ereport() with no damage done.
1127 : : * 2. Context-type-specific routine sets up all type-specific fields of
1128 : : * the header (those beyond MemoryContextData proper), as well as any
1129 : : * other management fields it needs to have a fully valid context.
1130 : : * Usually, failure in this step is impossible, but if it's possible
1131 : : * the initial space allocation should be freed before ereport'ing.
1132 : : * 3. Context-type-specific routine calls MemoryContextCreate() to fill in
1133 : : * the generic header fields and link the context into the context tree.
1134 : : * 4. We return to the context-type-specific routine, which finishes
1135 : : * up type-specific initialization. This routine can now do things
1136 : : * that might fail (like allocate more memory), so long as it's
1137 : : * sure the node is left in a state that delete will handle.
1138 : : *
1139 : : * node: the as-yet-uninitialized common part of the context header node.
1140 : : * tag: NodeTag code identifying the memory context type.
1141 : : * method_id: MemoryContextMethodID of the context-type being created.
1142 : : * parent: parent context, or NULL if this will be a top-level context.
1143 : : * name: name of context (must be statically allocated).
1144 : : *
1145 : : * Context routines generally assume that MemoryContextCreate can't fail,
1146 : : * so this can contain Assert but not elog/ereport.
1147 : : */
1148 : : void
1149 : 3029796 : MemoryContextCreate(MemoryContext node,
1150 : : NodeTag tag,
1151 : : MemoryContextMethodID method_id,
1152 : : MemoryContext parent,
1153 : : const char *name)
1154 : : {
1155 : : /* Creating new memory contexts is not allowed in a critical section */
1156 [ + - ]: 3029796 : Assert(CritSectionCount == 0);
1157 : :
1158 : : /* Validate parent, to help prevent crazy context linkages */
1159 [ + + + - : 3029796 : Assert(parent == NULL || MemoryContextIsValid(parent));
+ + + - +
- ]
1160 [ + - ]: 3029796 : Assert(node != parent);
1161 : :
1162 : : /* Initialize all standard fields of memory context header */
1163 : 3029796 : node->type = tag;
1164 : 3029796 : node->isReset = true;
1165 : 3029796 : node->methods = &mcxt_methods[method_id];
1166 : 3029796 : node->parent = parent;
1167 : 3029796 : node->firstchild = NULL;
1168 : 3029796 : node->mem_allocated = 0;
1169 : 3029796 : node->prevchild = NULL;
1170 : 3029796 : node->name = name;
1171 : 3029796 : node->ident = NULL;
1172 : 3029796 : node->reset_cbs = NULL;
1173 : :
1174 : : /* OK to link node into context tree */
1175 [ + + ]: 3029796 : if (parent)
1176 : : {
1177 : 3029787 : node->nextchild = parent->firstchild;
1178 [ + + ]: 3029787 : if (parent->firstchild != NULL)
1179 : 1390928 : parent->firstchild->prevchild = node;
1180 : 3029787 : parent->firstchild = node;
1181 : : /* inherit allowInCritSection flag from parent */
1182 : 3029787 : node->allowInCritSection = parent->allowInCritSection;
1183 : 3029787 : }
1184 : : else
1185 : : {
1186 : 9 : node->nextchild = NULL;
1187 : 9 : node->allowInCritSection = false;
1188 : : }
1189 : 3029796 : }
1190 : :
1191 : : /*
1192 : : * MemoryContextAllocationFailure
1193 : : * For use by MemoryContextMethods implementations to handle when malloc
1194 : : * returns NULL. The behavior is specific to whether MCXT_ALLOC_NO_OOM
1195 : : * is in 'flags'.
1196 : : */
1197 : : void *
1198 : 0 : MemoryContextAllocationFailure(MemoryContext context, Size size, int flags)
1199 : : {
1200 [ # # ]: 0 : if ((flags & MCXT_ALLOC_NO_OOM) == 0)
1201 : : {
1202 [ # # ]: 0 : if (TopMemoryContext)
1203 : 0 : MemoryContextStats(TopMemoryContext);
1204 [ # # # # ]: 0 : ereport(ERROR,
1205 : : (errcode(ERRCODE_OUT_OF_MEMORY),
1206 : : errmsg("out of memory"),
1207 : : errdetail("Failed on request of size %zu in memory context \"%s\".",
1208 : : size, context->name)));
1209 : 0 : }
1210 : 0 : return NULL;
1211 : : }
1212 : :
1213 : : /*
1214 : : * MemoryContextSizeFailure
1215 : : * For use by MemoryContextMethods implementations to handle invalid
1216 : : * memory allocation request sizes.
1217 : : */
1218 : : void
1219 : 0 : MemoryContextSizeFailure(MemoryContext context, Size size, int flags)
1220 : : {
1221 [ # # # # ]: 0 : elog(ERROR, "invalid memory alloc request size %zu", size);
1222 : 0 : }
1223 : :
1224 : : /*
1225 : : * MemoryContextAlloc
1226 : : * Allocate space within the specified context.
1227 : : *
1228 : : * This could be turned into a macro, but we'd have to import
1229 : : * nodes/memnodes.h into postgres.h which seems a bad idea.
1230 : : */
1231 : : void *
1232 : 9055178 : MemoryContextAlloc(MemoryContext context, Size size)
1233 : : {
1234 : 9055178 : void *ret;
1235 : :
1236 [ + - + + : 9055178 : Assert(MemoryContextIsValid(context));
+ + + + ]
1237 [ + + + - ]: 9055178 : AssertNotInCriticalSection(context);
1238 : :
1239 : 9055178 : context->isReset = false;
1240 : :
1241 : : /*
1242 : : * For efficiency reasons, we purposefully offload the handling of
1243 : : * allocation failures to the MemoryContextMethods implementation as this
1244 : : * allows these checks to be performed only when an actual malloc needs to
1245 : : * be done to request more memory from the OS. Additionally, not having
1246 : : * to execute any instructions after this call allows the compiler to use
1247 : : * the sibling call optimization. If you're considering adding code after
1248 : : * this call, consider making it the responsibility of the 'alloc'
1249 : : * function instead.
1250 : : */
1251 : 9055178 : ret = context->methods->alloc(context, size, 0);
1252 : :
1253 : 9055178 : VALGRIND_MEMPOOL_ALLOC(context, ret, size);
1254 : :
1255 : 18110356 : return ret;
1256 : 9055178 : }
1257 : :
1258 : : /*
1259 : : * MemoryContextAllocZero
1260 : : * Like MemoryContextAlloc, but clears allocated memory
1261 : : *
1262 : : * We could just call MemoryContextAlloc then clear the memory, but this
1263 : : * is a very common combination, so we provide the combined operation.
1264 : : */
1265 : : void *
1266 : 3622939 : MemoryContextAllocZero(MemoryContext context, Size size)
1267 : : {
1268 : 3622939 : void *ret;
1269 : :
1270 [ + - + + : 3622939 : Assert(MemoryContextIsValid(context));
+ - + - ]
1271 [ - + # # ]: 3622939 : AssertNotInCriticalSection(context);
1272 : :
1273 : 3622939 : context->isReset = false;
1274 : :
1275 : 3622939 : ret = context->methods->alloc(context, size, 0);
1276 : :
1277 : 3622939 : VALGRIND_MEMPOOL_ALLOC(context, ret, size);
1278 : :
1279 [ + + + - : 32557127 : MemSetAligned(ret, 0, size);
+ + + + ]
1280 : :
1281 : 7245878 : return ret;
1282 : 3622939 : }
1283 : :
1284 : : /*
1285 : : * MemoryContextAllocExtended
1286 : : * Allocate space within the specified context using the given flags.
1287 : : */
1288 : : void *
1289 : 512386 : MemoryContextAllocExtended(MemoryContext context, Size size, int flags)
1290 : : {
1291 : 512386 : void *ret;
1292 : :
1293 [ + - - + : 512386 : Assert(MemoryContextIsValid(context));
# # # # ]
1294 [ + + + - ]: 512386 : AssertNotInCriticalSection(context);
1295 : :
1296 [ + + + - ]: 512386 : if (!((flags & MCXT_ALLOC_HUGE) != 0 ? AllocHugeSizeIsValid(size) :
1297 : 332788 : AllocSizeIsValid(size)))
1298 [ # # # # ]: 0 : elog(ERROR, "invalid memory alloc request size %zu", size);
1299 : :
1300 : 512386 : context->isReset = false;
1301 : :
1302 : 512386 : ret = context->methods->alloc(context, size, flags);
1303 [ - + ]: 512386 : if (unlikely(ret == NULL))
1304 : 0 : return NULL;
1305 : :
1306 : 512386 : VALGRIND_MEMPOOL_ALLOC(context, ret, size);
1307 : :
1308 [ + + ]: 512386 : if ((flags & MCXT_ALLOC_ZERO) != 0)
1309 [ + - + - : 251696 : MemSetAligned(ret, 0, size);
+ + + + ]
1310 : :
1311 : 512386 : return ret;
1312 : 512386 : }
1313 : :
1314 : : /*
1315 : : * HandleLogMemoryContextInterrupt
1316 : : * Handle receipt of an interrupt indicating logging of memory
1317 : : * contexts.
1318 : : *
1319 : : * All the actual work is deferred to ProcessLogMemoryContextInterrupt(),
1320 : : * because we cannot safely emit a log message inside the signal handler.
1321 : : */
1322 : : void
1323 : 2 : HandleLogMemoryContextInterrupt(void)
1324 : : {
1325 : 2 : InterruptPending = true;
1326 : 2 : LogMemoryContextPending = true;
1327 : : /* latch will be set by procsignal_sigusr1_handler */
1328 : 2 : }
1329 : :
1330 : : /*
1331 : : * ProcessLogMemoryContextInterrupt
1332 : : * Perform logging of memory contexts of this backend process.
1333 : : *
1334 : : * Any backend that participates in ProcSignal signaling must arrange
1335 : : * to call this function if we see LogMemoryContextPending set.
1336 : : * It is called from CHECK_FOR_INTERRUPTS(), which is enough because
1337 : : * the target process for logging of memory contexts is a backend.
1338 : : */
1339 : : void
1340 : 2 : ProcessLogMemoryContextInterrupt(void)
1341 : : {
1342 : 2 : LogMemoryContextPending = false;
1343 : :
1344 : : /*
1345 : : * Exit immediately if memory context logging is already in progress. This
1346 : : * prevents recursive calls, which could occur if logging is requested
1347 : : * repeatedly and rapidly, potentially leading to infinite recursion and a
1348 : : * crash.
1349 : : */
1350 [ - + ]: 2 : if (LogMemoryContextInProgress)
1351 : 0 : return;
1352 : 2 : LogMemoryContextInProgress = true;
1353 : :
1354 [ - + ]: 2 : PG_TRY();
1355 : : {
1356 : : /*
1357 : : * Use LOG_SERVER_ONLY to prevent this message from being sent to the
1358 : : * connected client.
1359 : : */
1360 [ - + + - ]: 2 : ereport(LOG_SERVER_ONLY,
1361 : : (errhidestmt(true),
1362 : : errhidecontext(true),
1363 : : errmsg("logging memory contexts of PID %d", MyProcPid)));
1364 : :
1365 : : /*
1366 : : * When a backend process is consuming huge memory, logging all its
1367 : : * memory contexts might overrun available disk space. To prevent
1368 : : * this, we limit the depth of the hierarchy, as well as the number of
1369 : : * child contexts to log per parent to 100.
1370 : : *
1371 : : * As with MemoryContextStats(), we suppose that practical cases where
1372 : : * the dump gets long will typically be huge numbers of siblings under
1373 : : * the same parent context; while the additional debugging value from
1374 : : * seeing details about individual siblings beyond 100 will not be
1375 : : * large.
1376 : : */
1377 : 2 : MemoryContextStatsDetail(TopMemoryContext, 100, 100, false);
1378 : : }
1379 : 2 : PG_FINALLY();
1380 : : {
1381 : 2 : LogMemoryContextInProgress = false;
1382 : : }
1383 [ + - ]: 2 : PG_END_TRY();
1384 : 2 : }
1385 : :
1386 : : void *
1387 : 58211768 : palloc(Size size)
1388 : : {
1389 : : /* duplicates MemoryContextAlloc to avoid increased overhead */
1390 : 58211768 : void *ret;
1391 : 58211768 : MemoryContext context = CurrentMemoryContext;
1392 : :
1393 [ + - + + : 58211768 : Assert(MemoryContextIsValid(context));
+ - + + ]
1394 [ + + + - ]: 58211768 : AssertNotInCriticalSection(context);
1395 : :
1396 : 58211768 : context->isReset = false;
1397 : :
1398 : : /*
1399 : : * For efficiency reasons, we purposefully offload the handling of
1400 : : * allocation failures to the MemoryContextMethods implementation as this
1401 : : * allows these checks to be performed only when an actual malloc needs to
1402 : : * be done to request more memory from the OS. Additionally, not having
1403 : : * to execute any instructions after this call allows the compiler to use
1404 : : * the sibling call optimization. If you're considering adding code after
1405 : : * this call, consider making it the responsibility of the 'alloc'
1406 : : * function instead.
1407 : : */
1408 : 58211768 : ret = context->methods->alloc(context, size, 0);
1409 : : /* We expect OOM to be handled by the alloc function */
1410 [ + - ]: 58211768 : Assert(ret != NULL);
1411 : 58211768 : VALGRIND_MEMPOOL_ALLOC(context, ret, size);
1412 : :
1413 : 116423536 : return ret;
1414 : 58211768 : }
1415 : :
1416 : : void *
1417 : 39163258 : palloc0(Size size)
1418 : : {
1419 : : /* duplicates MemoryContextAllocZero to avoid increased overhead */
1420 : 39163258 : void *ret;
1421 : 39163258 : MemoryContext context = CurrentMemoryContext;
1422 : :
1423 [ + - + + : 39163258 : Assert(MemoryContextIsValid(context));
+ - + + ]
1424 [ - + # # ]: 39163258 : AssertNotInCriticalSection(context);
1425 : :
1426 : 39163258 : context->isReset = false;
1427 : :
1428 : 39163258 : ret = context->methods->alloc(context, size, 0);
1429 : : /* We expect OOM to be handled by the alloc function */
1430 [ + - ]: 39163258 : Assert(ret != NULL);
1431 : 39163258 : VALGRIND_MEMPOOL_ALLOC(context, ret, size);
1432 : :
1433 [ + + + - : 395342938 : MemSetAligned(ret, 0, size);
+ + + + ]
1434 : :
1435 : 78326516 : return ret;
1436 : 39163258 : }
1437 : :
1438 : : void *
1439 : 3866529 : palloc_extended(Size size, int flags)
1440 : : {
1441 : : /* duplicates MemoryContextAllocExtended to avoid increased overhead */
1442 : 3866529 : void *ret;
1443 : 3866529 : MemoryContext context = CurrentMemoryContext;
1444 : :
1445 [ + - - + : 3866529 : Assert(MemoryContextIsValid(context));
# # # # ]
1446 [ - + # # ]: 3866529 : AssertNotInCriticalSection(context);
1447 : :
1448 : 3866529 : context->isReset = false;
1449 : :
1450 : 3866529 : ret = context->methods->alloc(context, size, flags);
1451 [ - + ]: 3866529 : if (unlikely(ret == NULL))
1452 : : {
1453 : : /* NULL can be returned only when using MCXT_ALLOC_NO_OOM */
1454 [ # # ]: 0 : Assert(flags & MCXT_ALLOC_NO_OOM);
1455 : 0 : return NULL;
1456 : : }
1457 : :
1458 : 3866529 : VALGRIND_MEMPOOL_ALLOC(context, ret, size);
1459 : :
1460 [ + + ]: 3866529 : if ((flags & MCXT_ALLOC_ZERO) != 0)
1461 [ + - + - : 4 : MemSetAligned(ret, 0, size);
+ - # # ]
1462 : :
1463 : 3866529 : return ret;
1464 : 3866529 : }
1465 : :
1466 : : /*
1467 : : * MemoryContextAllocAligned
1468 : : * Allocate 'size' bytes of memory in 'context' aligned to 'alignto'
1469 : : * bytes.
1470 : : *
1471 : : * Currently, we align addresses by requesting additional bytes from the
1472 : : * MemoryContext's standard allocator function and then aligning the returned
1473 : : * address by the required alignment. This means that the given MemoryContext
1474 : : * must support providing us with a chunk of memory that's larger than 'size'.
1475 : : * For allocators such as Slab, that's not going to work, as slab only allows
1476 : : * chunks of the size that's specified when the context is created.
1477 : : *
1478 : : * 'alignto' must be a power of 2.
1479 : : * 'flags' may be 0 or set the same as MemoryContextAllocExtended().
1480 : : */
1481 : : void *
1482 : 77689 : MemoryContextAllocAligned(MemoryContext context,
1483 : : Size size, Size alignto, int flags)
1484 : : {
1485 : 77689 : MemoryChunk *alignedchunk;
1486 : 77689 : Size alloc_size;
1487 : 77689 : void *unaligned;
1488 : 77689 : void *aligned;
1489 : :
1490 : : /*
1491 : : * Restrict alignto to ensure that it can fit into the "value" field of
1492 : : * the redirection MemoryChunk, and that the distance back to the start of
1493 : : * the unaligned chunk will fit into the space available for that. This
1494 : : * isn't a limitation in practice, since it wouldn't make much sense to
1495 : : * waste that much space.
1496 : : */
1497 [ + - ]: 77689 : Assert(alignto < (128 * 1024 * 1024));
1498 : :
1499 : : /* ensure alignto is a power of 2 */
1500 [ + - ]: 77689 : Assert((alignto & (alignto - 1)) == 0);
1501 : :
1502 : : /*
1503 : : * If the alignment requirements are less than what we already guarantee
1504 : : * then just use the standard allocation function.
1505 : : */
1506 [ - + ]: 77689 : if (unlikely(alignto <= MAXIMUM_ALIGNOF))
1507 : 0 : return MemoryContextAllocExtended(context, size, flags);
1508 : :
1509 : : /*
1510 : : * We implement aligned pointers by simply allocating enough memory for
1511 : : * the requested size plus the alignment and an additional "redirection"
1512 : : * MemoryChunk. This additional MemoryChunk is required for operations
1513 : : * such as pfree when used on the pointer returned by this function. We
1514 : : * use this redirection MemoryChunk in order to find the pointer to the
1515 : : * memory that was returned by the MemoryContextAllocExtended call below.
1516 : : * We do that by "borrowing" the block offset field and instead of using
1517 : : * that to find the offset into the owning block, we use it to find the
1518 : : * original allocated address.
1519 : : *
1520 : : * Here we must allocate enough extra memory so that we can still align
1521 : : * the pointer returned by MemoryContextAllocExtended and also have enough
1522 : : * space for the redirection MemoryChunk. Since allocations will already
1523 : : * be at least aligned by MAXIMUM_ALIGNOF, we can subtract that amount
1524 : : * from the allocation size to save a little memory.
1525 : : */
1526 : 77689 : alloc_size = size + PallocAlignedExtraBytes(alignto);
1527 : :
1528 : : #ifdef MEMORY_CONTEXT_CHECKING
1529 : : /* ensure there's space for a sentinel byte */
1530 : 77689 : alloc_size += 1;
1531 : : #endif
1532 : :
1533 : : /*
1534 : : * Perform the actual allocation, but do not pass down MCXT_ALLOC_ZERO.
1535 : : * This ensures that wasted bytes beyond the aligned chunk do not become
1536 : : * DEFINED.
1537 : : */
1538 : 155378 : unaligned = MemoryContextAllocExtended(context, alloc_size,
1539 : 77689 : flags & ~MCXT_ALLOC_ZERO);
1540 : :
1541 : : /* compute the aligned pointer */
1542 : 77689 : aligned = (void *) TYPEALIGN(alignto, (char *) unaligned +
1543 : : sizeof(MemoryChunk));
1544 : :
1545 : 77689 : alignedchunk = PointerGetMemoryChunk(aligned);
1546 : :
1547 : : /*
1548 : : * We set the redirect MemoryChunk so that the block offset calculation is
1549 : : * used to point back to the 'unaligned' allocated chunk. This allows us
1550 : : * to use MemoryChunkGetBlock() to find the unaligned chunk when we need
1551 : : * to perform operations such as pfree() and repalloc().
1552 : : *
1553 : : * We store 'alignto' in the MemoryChunk's 'value' so that we know what
1554 : : * the alignment was set to should we ever be asked to realloc this
1555 : : * pointer.
1556 : : */
1557 : 77689 : MemoryChunkSetHdrMask(alignedchunk, unaligned, alignto,
1558 : : MCTX_ALIGNED_REDIRECT_ID);
1559 : :
1560 : : /* double check we produced a correctly aligned pointer */
1561 [ + - ]: 77689 : Assert((void *) TYPEALIGN(alignto, aligned) == aligned);
1562 : :
1563 : : #ifdef MEMORY_CONTEXT_CHECKING
1564 : 77689 : alignedchunk->requested_size = size;
1565 : : /* set mark to catch clobber of "unused" space */
1566 : 77689 : set_sentinel(aligned, size);
1567 : : #endif
1568 : :
1569 : : /*
1570 : : * MemoryContextAllocExtended marked the whole unaligned chunk as a
1571 : : * vchunk. Undo that, instead making just the aligned chunk be a vchunk.
1572 : : * This prevents Valgrind from complaining that the vchunk is possibly
1573 : : * leaked, since only pointers to the aligned chunk will exist.
1574 : : *
1575 : : * After these calls, the aligned chunk will be marked UNDEFINED, and all
1576 : : * the rest of the unaligned chunk (the redirection chunk header, the
1577 : : * padding bytes before it, and any wasted trailing bytes) will be marked
1578 : : * NOACCESS, which is what we want.
1579 : : */
1580 : 77689 : VALGRIND_MEMPOOL_FREE(context, unaligned);
1581 : 77689 : VALGRIND_MEMPOOL_ALLOC(context, aligned, size);
1582 : :
1583 : : /* Now zero (and make DEFINED) just the aligned chunk, if requested */
1584 [ + + ]: 77689 : if ((flags & MCXT_ALLOC_ZERO) != 0)
1585 [ + - + - : 3866310 : MemSetAligned(aligned, 0, size);
- + + + ]
1586 : :
1587 : 77689 : return aligned;
1588 : 77689 : }
1589 : :
1590 : : /*
1591 : : * palloc_aligned
1592 : : * Allocate 'size' bytes returning a pointer that's aligned to the
1593 : : * 'alignto' boundary.
1594 : : *
1595 : : * Currently, we align addresses by requesting additional bytes from the
1596 : : * MemoryContext's standard allocator function and then aligning the returned
1597 : : * address by the required alignment. This means that the given MemoryContext
1598 : : * must support providing us with a chunk of memory that's larger than 'size'.
1599 : : * For allocators such as Slab, that's not going to work, as slab only allows
1600 : : * chunks of the size that's specified when the context is created.
1601 : : *
1602 : : * 'alignto' must be a power of 2.
1603 : : * 'flags' may be 0 or set the same as MemoryContextAllocExtended().
1604 : : */
1605 : : void *
1606 : 67830 : palloc_aligned(Size size, Size alignto, int flags)
1607 : : {
1608 : 67830 : return MemoryContextAllocAligned(CurrentMemoryContext, size, alignto, flags);
1609 : : }
1610 : :
1611 : : /*
1612 : : * pfree
1613 : : * Release an allocated chunk.
1614 : : */
1615 : : void
1616 : 50990794 : pfree(void *pointer)
1617 : : {
1618 : : #ifdef USE_VALGRIND
1619 : : MemoryContext context = GetMemoryChunkContext(pointer);
1620 : : #endif
1621 : :
1622 : 50990794 : MCXT_METHOD(pointer, free_p) (pointer);
1623 : :
1624 : 50990794 : VALGRIND_MEMPOOL_FREE(context, pointer);
1625 : 50990794 : }
1626 : :
1627 : : /*
1628 : : * repalloc
1629 : : * Adjust the size of a previously allocated chunk.
1630 : : */
1631 : : void *
1632 : 221829 : repalloc(void *pointer, Size size)
1633 : : {
1634 : : #if defined(USE_ASSERT_CHECKING) || defined(USE_VALGRIND)
1635 : 221829 : MemoryContext context = GetMemoryChunkContext(pointer);
1636 : : #endif
1637 : 221829 : void *ret;
1638 : :
1639 [ - + # # ]: 221829 : AssertNotInCriticalSection(context);
1640 : :
1641 : : /* isReset must be false already */
1642 [ + - ]: 221829 : Assert(!context->isReset);
1643 : :
1644 : : /*
1645 : : * For efficiency reasons, we purposefully offload the handling of
1646 : : * allocation failures to the MemoryContextMethods implementation as this
1647 : : * allows these checks to be performed only when an actual malloc needs to
1648 : : * be done to request more memory from the OS. Additionally, not having
1649 : : * to execute any instructions after this call allows the compiler to use
1650 : : * the sibling call optimization. If you're considering adding code after
1651 : : * this call, consider making it the responsibility of the 'realloc'
1652 : : * function instead.
1653 : : */
1654 : 221829 : ret = MCXT_METHOD(pointer, realloc) (pointer, size, 0);
1655 : :
1656 : 221829 : VALGRIND_MEMPOOL_CHANGE(context, pointer, ret, size);
1657 : :
1658 : 443658 : return ret;
1659 : 221829 : }
1660 : :
1661 : : /*
1662 : : * repalloc_extended
1663 : : * Adjust the size of a previously allocated chunk,
1664 : : * with HUGE and NO_OOM options.
1665 : : */
1666 : : void *
1667 : 12742 : repalloc_extended(void *pointer, Size size, int flags)
1668 : : {
1669 : : #if defined(USE_ASSERT_CHECKING) || defined(USE_VALGRIND)
1670 : 12742 : MemoryContext context = GetMemoryChunkContext(pointer);
1671 : : #endif
1672 : 12742 : void *ret;
1673 : :
1674 [ - + # # ]: 12742 : AssertNotInCriticalSection(context);
1675 : :
1676 : : /* isReset must be false already */
1677 [ + - ]: 12742 : Assert(!context->isReset);
1678 : :
1679 : : /*
1680 : : * For efficiency reasons, we purposefully offload the handling of
1681 : : * allocation failures to the MemoryContextMethods implementation as this
1682 : : * allows these checks to be performed only when an actual malloc needs to
1683 : : * be done to request more memory from the OS. Additionally, not having
1684 : : * to execute any instructions after this call allows the compiler to use
1685 : : * the sibling call optimization. If you're considering adding code after
1686 : : * this call, consider making it the responsibility of the 'realloc'
1687 : : * function instead.
1688 : : */
1689 : 12742 : ret = MCXT_METHOD(pointer, realloc) (pointer, size, flags);
1690 [ - + ]: 12742 : if (unlikely(ret == NULL))
1691 : 0 : return NULL;
1692 : :
1693 : 12742 : VALGRIND_MEMPOOL_CHANGE(context, pointer, ret, size);
1694 : :
1695 : 12742 : return ret;
1696 : 12742 : }
1697 : :
1698 : : /*
1699 : : * repalloc0
1700 : : * Adjust the size of a previously allocated chunk and zero out the added
1701 : : * space.
1702 : : */
1703 : : void *
1704 : 6729 : repalloc0(void *pointer, Size oldsize, Size size)
1705 : : {
1706 : 6729 : void *ret;
1707 : :
1708 : : /* catch wrong argument order */
1709 [ + - ]: 6729 : if (unlikely(oldsize > size))
1710 [ # # # # ]: 0 : elog(ERROR, "invalid repalloc0 call: oldsize %zu, new size %zu",
1711 : : oldsize, size);
1712 : :
1713 : 6729 : ret = repalloc(pointer, size);
1714 : 6729 : memset((char *) ret + oldsize, 0, (size - oldsize));
1715 : 13458 : return ret;
1716 : 6729 : }
1717 : :
1718 : : /*
1719 : : * MemoryContextAllocHuge
1720 : : * Allocate (possibly-expansive) space within the specified context.
1721 : : *
1722 : : * See considerations in comment at MaxAllocHugeSize.
1723 : : */
1724 : : void *
1725 : 164 : MemoryContextAllocHuge(MemoryContext context, Size size)
1726 : : {
1727 : 164 : void *ret;
1728 : :
1729 [ + - - + : 164 : Assert(MemoryContextIsValid(context));
# # # # ]
1730 [ - + # # ]: 164 : AssertNotInCriticalSection(context);
1731 : :
1732 : 164 : context->isReset = false;
1733 : :
1734 : : /*
1735 : : * For efficiency reasons, we purposefully offload the handling of
1736 : : * allocation failures to the MemoryContextMethods implementation as this
1737 : : * allows these checks to be performed only when an actual malloc needs to
1738 : : * be done to request more memory from the OS. Additionally, not having
1739 : : * to execute any instructions after this call allows the compiler to use
1740 : : * the sibling call optimization. If you're considering adding code after
1741 : : * this call, consider making it the responsibility of the 'alloc'
1742 : : * function instead.
1743 : : */
1744 : 164 : ret = context->methods->alloc(context, size, MCXT_ALLOC_HUGE);
1745 : :
1746 : 164 : VALGRIND_MEMPOOL_ALLOC(context, ret, size);
1747 : :
1748 : 328 : return ret;
1749 : 164 : }
1750 : :
1751 : : /*
1752 : : * repalloc_huge
1753 : : * Adjust the size of a previously allocated chunk, permitting a large
1754 : : * value. The previous allocation need not have been "huge".
1755 : : */
1756 : : void *
1757 : 12659 : repalloc_huge(void *pointer, Size size)
1758 : : {
1759 : : /* this one seems not worth its own implementation */
1760 : 12659 : return repalloc_extended(pointer, size, MCXT_ALLOC_HUGE);
1761 : : }
1762 : :
1763 : : /*
1764 : : * MemoryContextStrdup
1765 : : * Like strdup(), but allocate from the specified context
1766 : : */
1767 : : char *
1768 : 2680607 : MemoryContextStrdup(MemoryContext context, const char *string)
1769 : : {
1770 : 2680607 : char *nstr;
1771 : 2680607 : Size len = strlen(string) + 1;
1772 : :
1773 : 2680607 : nstr = (char *) MemoryContextAlloc(context, len);
1774 : :
1775 : 2680607 : memcpy(nstr, string, len);
1776 : :
1777 : 5361214 : return nstr;
1778 : 2680607 : }
1779 : :
1780 : : char *
1781 : 2545134 : pstrdup(const char *in)
1782 : : {
1783 : 2545134 : return MemoryContextStrdup(CurrentMemoryContext, in);
1784 : : }
1785 : :
1786 : : /*
1787 : : * pnstrdup
1788 : : * Like pstrdup(), but append null byte to a
1789 : : * not-necessarily-null-terminated input string.
1790 : : */
1791 : : char *
1792 : 169408 : pnstrdup(const char *in, Size len)
1793 : : {
1794 : 169408 : char *out;
1795 : :
1796 : 169408 : len = strnlen(in, len);
1797 : :
1798 : 169408 : out = palloc(len + 1);
1799 : 169408 : memcpy(out, in, len);
1800 : 169408 : out[len] = '\0';
1801 : :
1802 : 338816 : return out;
1803 : 169408 : }
1804 : :
1805 : : /*
1806 : : * Make copy of string with all trailing newline characters removed.
1807 : : */
1808 : : char *
1809 : 1 : pchomp(const char *in)
1810 : : {
1811 : 1 : size_t n;
1812 : :
1813 : 1 : n = strlen(in);
1814 [ - + + + ]: 2 : while (n > 0 && in[n - 1] == '\n')
1815 : 1 : n--;
1816 : 2 : return pnstrdup(in, n);
1817 : 1 : }
|