LCOV - code coverage report
Current view: top level - src/include/utils - memutils.h (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 61.0 % 41 25
Test Date: 2026-03-03 14:15:12 Functions: 100.0 % 1 1
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * memutils.h
       4              :  *    This file contains declarations for memory allocation utility
       5              :  *    functions.  These are functions that are not quite widely used
       6              :  *    enough to justify going in utils/palloc.h, but are still part
       7              :  *    of the API of the memory management subsystem.
       8              :  *
       9              :  *
      10              :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
      11              :  * Portions Copyright (c) 1994, Regents of the University of California
      12              :  *
      13              :  * src/include/utils/memutils.h
      14              :  *
      15              :  *-------------------------------------------------------------------------
      16              :  */
      17              : #ifndef MEMUTILS_H
      18              : #define MEMUTILS_H
      19              : 
      20              : #include "nodes/memnodes.h"
      21              : 
      22              : 
      23              : /*
      24              :  * MaxAllocSize, MaxAllocHugeSize
      25              :  *      Quasi-arbitrary limits on size of allocations.
      26              :  *
      27              :  * Note:
      28              :  *      There is no guarantee that smaller allocations will succeed, but
      29              :  *      larger requests will be summarily denied.
      30              :  *
      31              :  * palloc() enforces MaxAllocSize, chosen to correspond to the limiting size
      32              :  * of varlena objects under TOAST.  See VARSIZE_4B() and related macros in
      33              :  * varatt.h.  Many datatypes assume that any allocatable size can be
      34              :  * represented in a varlena header.  This limit also permits a caller to use
      35              :  * an "int" variable for an index into or length of an allocation.  Callers
      36              :  * careful to avoid these hazards can access the higher limit with
      37              :  * MemoryContextAllocHuge().  Both limits permit code to assume that it may
      38              :  * compute twice an allocation's size without overflow.
      39              :  */
      40              : #define MaxAllocSize    ((Size) 0x3fffffff) /* 1 gigabyte - 1 */
      41              : 
      42              : #define AllocSizeIsValid(size)  ((Size) (size) <= MaxAllocSize)
      43              : 
      44              : /* Must be less than SIZE_MAX */
      45              : #define MaxAllocHugeSize    (SIZE_MAX / 2)
      46              : 
      47              : #define InvalidAllocSize    SIZE_MAX
      48              : 
      49              : #define AllocHugeSizeIsValid(size)  ((Size) (size) <= MaxAllocHugeSize)
      50              : 
      51              : 
      52              : /*
      53              :  * Standard top-level memory contexts.
      54              :  *
      55              :  * Only TopMemoryContext and ErrorContext are initialized by
      56              :  * MemoryContextInit() itself.
      57              :  */
      58              : extern PGDLLIMPORT MemoryContext TopMemoryContext;
      59              : extern PGDLLIMPORT MemoryContext ErrorContext;
      60              : extern PGDLLIMPORT MemoryContext PostmasterContext;
      61              : extern PGDLLIMPORT MemoryContext CacheMemoryContext;
      62              : extern PGDLLIMPORT MemoryContext MessageContext;
      63              : extern PGDLLIMPORT MemoryContext TopTransactionContext;
      64              : extern PGDLLIMPORT MemoryContext CurTransactionContext;
      65              : 
      66              : /* This is a transient link to the active portal's memory context: */
      67              : extern PGDLLIMPORT MemoryContext PortalContext;
      68              : 
      69              : 
      70              : /*
      71              :  * Memory-context-type-independent functions in mcxt.c
      72              :  */
      73              : extern void MemoryContextInit(void);
      74              : extern void MemoryContextReset(MemoryContext context);
      75              : extern void MemoryContextDelete(MemoryContext context);
      76              : extern void MemoryContextResetOnly(MemoryContext context);
      77              : extern void MemoryContextResetChildren(MemoryContext context);
      78              : extern void MemoryContextDeleteChildren(MemoryContext context);
      79              : extern void MemoryContextSetIdentifier(MemoryContext context, const char *id);
      80              : extern void MemoryContextSetParent(MemoryContext context,
      81              :                                    MemoryContext new_parent);
      82              : extern MemoryContext GetMemoryChunkContext(void *pointer);
      83              : extern Size GetMemoryChunkSpace(void *pointer);
      84              : extern MemoryContext MemoryContextGetParent(MemoryContext context);
      85              : extern bool MemoryContextIsEmpty(MemoryContext context);
      86              : extern Size MemoryContextMemAllocated(MemoryContext context, bool recurse);
      87              : extern void MemoryContextMemConsumed(MemoryContext context,
      88              :                                      MemoryContextCounters *consumed);
      89              : extern void MemoryContextStats(MemoryContext context);
      90              : extern void MemoryContextStatsDetail(MemoryContext context,
      91              :                                      int max_level, int max_children,
      92              :                                      bool print_to_stderr);
      93              : extern void MemoryContextAllowInCriticalSection(MemoryContext context,
      94              :                                                 bool allow);
      95              : 
      96              : #ifdef MEMORY_CONTEXT_CHECKING
      97              : extern void MemoryContextCheck(MemoryContext context);
      98              : #endif
      99              : 
     100              : /* Handy macro for copying and assigning context ID ... but note double eval */
     101              : #define MemoryContextCopyAndSetIdentifier(cxt, id) \
     102              :     MemoryContextSetIdentifier(cxt, MemoryContextStrdup(cxt, id))
     103              : 
     104              : extern void HandleLogMemoryContextInterrupt(void);
     105              : extern void ProcessLogMemoryContextInterrupt(void);
     106              : 
     107              : /*
     108              :  * Memory-context-type-specific functions
     109              :  */
     110              : 
     111              : /* aset.c */
     112              : extern MemoryContext AllocSetContextCreateInternal(MemoryContext parent,
     113              :                                                    const char *name,
     114              :                                                    Size minContextSize,
     115              :                                                    Size initBlockSize,
     116              :                                                    Size maxBlockSize);
     117              : 
     118              : /*
     119              :  * This wrapper macro exists to check for non-constant strings used as context
     120              :  * names; that's no longer supported.  (Use MemoryContextSetIdentifier if you
     121              :  * want to provide a variable identifier.)
     122              :  */
     123              : #ifdef HAVE__BUILTIN_CONSTANT_P
     124              : #define AllocSetContextCreate(parent, name, ...) \
     125              :     (StaticAssertExpr(__builtin_constant_p(name), \
     126              :                       "memory context names must be constant strings"), \
     127              :      AllocSetContextCreateInternal(parent, name, __VA_ARGS__))
     128              : #else
     129              : #define AllocSetContextCreate \
     130              :     AllocSetContextCreateInternal
     131              : #endif
     132              : 
     133              : /* slab.c */
     134              : extern MemoryContext SlabContextCreate(MemoryContext parent,
     135              :                                        const char *name,
     136              :                                        Size blockSize,
     137              :                                        Size chunkSize);
     138              : 
     139              : /* generation.c */
     140              : extern MemoryContext GenerationContextCreate(MemoryContext parent,
     141              :                                              const char *name,
     142              :                                              Size minContextSize,
     143              :                                              Size initBlockSize,
     144              :                                              Size maxBlockSize);
     145              : 
     146              : /* bump.c */
     147              : extern MemoryContext BumpContextCreate(MemoryContext parent,
     148              :                                        const char *name,
     149              :                                        Size minContextSize,
     150              :                                        Size initBlockSize,
     151              :                                        Size maxBlockSize);
     152              : 
     153              : /*
     154              :  * Recommended default alloc parameters, suitable for "ordinary" contexts
     155              :  * that might hold quite a lot of data.
     156              :  */
     157              : #define ALLOCSET_DEFAULT_MINSIZE   0
     158              : #define ALLOCSET_DEFAULT_INITSIZE  (8 * 1024)
     159              : #define ALLOCSET_DEFAULT_MAXSIZE   (8 * 1024 * 1024)
     160              : #define ALLOCSET_DEFAULT_SIZES \
     161              :     ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE
     162              : 
     163              : /*
     164              :  * Recommended alloc parameters for "small" contexts that are never expected
     165              :  * to contain much data (for example, a context to contain a query plan).
     166              :  */
     167              : #define ALLOCSET_SMALL_MINSIZE   0
     168              : #define ALLOCSET_SMALL_INITSIZE  (1 * 1024)
     169              : #define ALLOCSET_SMALL_MAXSIZE   (8 * 1024)
     170              : #define ALLOCSET_SMALL_SIZES \
     171              :     ALLOCSET_SMALL_MINSIZE, ALLOCSET_SMALL_INITSIZE, ALLOCSET_SMALL_MAXSIZE
     172              : 
     173              : /*
     174              :  * Recommended alloc parameters for contexts that should start out small,
     175              :  * but might sometimes grow big.
     176              :  */
     177              : #define ALLOCSET_START_SMALL_SIZES \
     178              :     ALLOCSET_SMALL_MINSIZE, ALLOCSET_SMALL_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE
     179              : 
     180              : 
     181              : /*
     182              :  * Threshold above which a request in an AllocSet context is certain to be
     183              :  * allocated separately (and thereby have constant allocation overhead).
     184              :  * Few callers should be interested in this, but tuplesort/tuplestore need
     185              :  * to know it.
     186              :  */
     187              : #define ALLOCSET_SEPARATE_THRESHOLD  8192
     188              : 
     189              : #define SLAB_DEFAULT_BLOCK_SIZE     (8 * 1024)
     190              : #define SLAB_LARGE_BLOCK_SIZE       (8 * 1024 * 1024)
     191              : 
     192              : /*
     193              :  * pg_memory_is_all_zeros
     194              :  *
     195              :  * Test if a memory region starting at "ptr" and of size "len" is full of
     196              :  * zeroes.
     197              :  *
     198              :  * The test is divided into multiple cases for safety reason and multiple
     199              :  * phases for efficiency.
     200              :  *
     201              :  * Case 1: len < sizeof(size_t) bytes, then byte-by-byte comparison.
     202              :  * Case 2: len < (sizeof(size_t) * 8 - 1) bytes:
     203              :  *       - Phase 1: byte-by-byte comparison, until the pointer is aligned.
     204              :  *       - Phase 2: size_t comparisons, with aligned pointers, up to the last
     205              :  *                  location possible.
     206              :  *       - Phase 3: byte-by-byte comparison, until the end location.
     207              :  * Case 3: len >= (sizeof(size_t) * 8) bytes, same as case 2 except that an
     208              :  *         additional phase is placed between Phase 1 and Phase 2, with
     209              :  *         (8 * sizeof(size_t)) comparisons using bitwise OR to encourage
     210              :  *         compilers to use SIMD instructions if available, up to the last
     211              :  *         aligned location possible.
     212              :  *
     213              :  * Case 1 and Case 2 are mandatory to ensure that we won't read beyond the
     214              :  * memory area.  This is portable for 32-bit and 64-bit architectures.
     215              :  *
     216              :  * Caller must ensure that "ptr" is not NULL.
     217              :  */
     218              : static inline bool
     219      1038264 : pg_memory_is_all_zeros(const void *ptr, size_t len)
     220              : {
     221      1038264 :     const unsigned char *p = (const unsigned char *) ptr;
     222      1038264 :     const unsigned char *end = &p[len];
     223      1038264 :     const unsigned char *aligned_end = (const unsigned char *)
     224      1038264 :         ((uintptr_t) end & (~(sizeof(size_t) - 1)));
     225              : 
     226      1038264 :     if (len < sizeof(size_t))
     227              :     {
     228            0 :         while (p < end)
     229              :         {
     230            0 :             if (*p++ != 0)
     231            0 :                 return false;
     232              :         }
     233            0 :         return true;
     234              :     }
     235              : 
     236              :     /* "len" in the [sizeof(size_t), sizeof(size_t) * 8 - 1] range */
     237      1038264 :     if (len < sizeof(size_t) * 8)
     238              :     {
     239              :         /* Compare bytes until the pointer "p" is aligned */
     240        14331 :         while (((uintptr_t) p & (sizeof(size_t) - 1)) != 0)
     241              :         {
     242            0 :             if (p == end)
     243            0 :                 return true;
     244            0 :             if (*p++ != 0)
     245            0 :                 return false;
     246              :         }
     247              : 
     248              :         /*
     249              :          * Compare remaining size_t-aligned chunks.
     250              :          *
     251              :          * There is no risk to read beyond the memory area, as "aligned_end"
     252              :          * cannot be higher than "end".
     253              :          */
     254        52209 :         for (; p < aligned_end; p += sizeof(size_t))
     255              :         {
     256        45393 :             if (*(const size_t *) p != 0)
     257         7515 :                 return false;
     258              :         }
     259              : 
     260              :         /* Compare remaining bytes until the end */
     261         6816 :         while (p < end)
     262              :         {
     263            0 :             if (*p++ != 0)
     264            0 :                 return false;
     265              :         }
     266         6816 :         return true;
     267              :     }
     268              : 
     269              :     /* "len" in the [sizeof(size_t) * 8, inf) range */
     270              : 
     271              :     /* Compare bytes until the pointer "p" is aligned */
     272      1023933 :     while (((uintptr_t) p & (sizeof(size_t) - 1)) != 0)
     273              :     {
     274            0 :         if (p == end)
     275            0 :             return true;
     276              : 
     277            0 :         if (*p++ != 0)
     278            0 :             return false;
     279              :     }
     280              : 
     281              :     /*
     282              :      * Compare 8 * sizeof(size_t) chunks at once.
     283              :      *
     284              :      * For performance reasons, we manually unroll this loop and purposefully
     285              :      * use bitwise-ORs to combine each comparison.  This prevents boolean
     286              :      * short-circuiting and lets the compiler know that it's safe to access
     287              :      * all 8 elements regardless of the result of the other comparisons.  This
     288              :      * seems to be enough to coax a few compilers into using SIMD
     289              :      * instructions.
     290              :      */
     291      2018306 :     for (; p < aligned_end - (sizeof(size_t) * 7); p += sizeof(size_t) * 8)
     292              :     {
     293      1562503 :         if ((((const size_t *) p)[0] != 0) | (((const size_t *) p)[1] != 0) |
     294      1562503 :             (((const size_t *) p)[2] != 0) | (((const size_t *) p)[3] != 0) |
     295      1562503 :             (((const size_t *) p)[4] != 0) | (((const size_t *) p)[5] != 0) |
     296      1562503 :             (((const size_t *) p)[6] != 0) | (((const size_t *) p)[7] != 0))
     297       568130 :             return false;
     298              :     }
     299              : 
     300              :     /*
     301              :      * Compare remaining size_t-aligned chunks.
     302              :      *
     303              :      * There is no risk to read beyond the memory area, as "aligned_end"
     304              :      * cannot be higher than "end".
     305              :      */
     306      2226729 :     for (; p < aligned_end; p += sizeof(size_t))
     307              :     {
     308      2205590 :         if (*(const size_t *) p != 0)
     309       434664 :             return false;
     310              :     }
     311              : 
     312              :     /* Compare remaining bytes until the end */
     313        21139 :     while (p < end)
     314              :     {
     315            0 :         if (*p++ != 0)
     316            0 :             return false;
     317              :     }
     318              : 
     319        21139 :     return true;
     320              : }
     321              : 
     322              : #endif                          /* MEMUTILS_H */
        

Generated by: LCOV version 2.0-1