LCOV - code coverage report
Current view: top level - src/include/utils - memutils_memorychunk.h (source / functions) Coverage Total Hit
Test: Code coverage Lines: 100.0 % 24 24
Test Date: 2026-01-26 10:56:24 Functions: 100.0 % 5 5
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 55.6 % 18 10

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * memutils_memorychunk.h
       4                 :             :  *        Here we define a struct named MemoryChunk which implementations of
       5                 :             :  *        MemoryContexts may use as a header for chunks of memory they allocate.
       6                 :             :  *
       7                 :             :  * MemoryChunk provides a lightweight header that a MemoryContext can use to
       8                 :             :  * store a reference back to the block which the given chunk is allocated on
       9                 :             :  * and also an additional 30-bits to store another value such as the size of
      10                 :             :  * the allocated chunk.
      11                 :             :  *
      12                 :             :  * Although MemoryChunks are used by each of our MemoryContexts, future
      13                 :             :  * implementations may choose to implement their own method for storing chunk
      14                 :             :  * headers.  The only requirement is that the header ends with an 8-byte value
      15                 :             :  * which the least significant 4-bits of are set to the MemoryContextMethodID
      16                 :             :  * of the given context.
      17                 :             :  *
      18                 :             :  * By default, a MemoryChunk is 8 bytes in size, however, when
      19                 :             :  * MEMORY_CONTEXT_CHECKING is defined the header becomes 16 bytes in size due
      20                 :             :  * to the additional requested_size field.  The MemoryContext may use this
      21                 :             :  * field for whatever they wish, but it is intended to be used for additional
      22                 :             :  * checks which are only done in MEMORY_CONTEXT_CHECKING builds.
      23                 :             :  *
      24                 :             :  * The MemoryChunk contains a uint64 field named 'hdrmask'.  This field is
      25                 :             :  * used to encode 4 separate pieces of information.  Starting with the least
      26                 :             :  * significant bits of 'hdrmask', the bit space is reserved as follows:
      27                 :             :  *
      28                 :             :  * 1.   4-bits to indicate the MemoryContextMethodID as defined by
      29                 :             :  *              MEMORY_CONTEXT_METHODID_MASK
      30                 :             :  * 2.   1-bit to denote an "external" chunk (see below)
      31                 :             :  * 3.   30-bits reserved for the MemoryContext to use for anything it
      32                 :             :  *              requires.  Most MemoryContexts likely want to store the size of the
      33                 :             :  *              chunk here.
      34                 :             :  * 4.   30-bits for the number of bytes that must be subtracted from the chunk
      35                 :             :  *              to obtain the address of the block that the chunk is stored on.
      36                 :             :  *
      37                 :             :  * If you're paying close attention, you'll notice this adds up to 65 bits
      38                 :             :  * rather than 64 bits.  This is because the highest-order bit of #3 is the
      39                 :             :  * same bit as the lowest-order bit of #4.  We can do this as we insist that
      40                 :             :  * the chunk and block pointers are both MAXALIGNed, therefore the relative
      41                 :             :  * offset between those will always be a MAXALIGNed value which means the
      42                 :             :  * lowest order bit is always 0.  When fetching the chunk to block offset we
      43                 :             :  * mask out the lowest-order bit to ensure it's still zero.
      44                 :             :  *
      45                 :             :  * In some cases, for example when memory allocations become large, it's
      46                 :             :  * possible fields 3 and 4 above are not large enough to store the values
      47                 :             :  * required for the chunk.  In this case, the MemoryContext can choose to mark
      48                 :             :  * the chunk as "external" by calling the MemoryChunkSetHdrMaskExternal()
      49                 :             :  * function.  When this is done, fields 3 and 4 are unavailable for use by the
      50                 :             :  * MemoryContext and it's up to the MemoryContext itself to devise its own
      51                 :             :  * method for getting the reference to the block.
      52                 :             :  *
      53                 :             :  * Interface:
      54                 :             :  *
      55                 :             :  * MemoryChunkSetHdrMask:
      56                 :             :  *              Used to set up a non-external MemoryChunk.
      57                 :             :  *
      58                 :             :  * MemoryChunkSetHdrMaskExternal:
      59                 :             :  *              Used to set up an externally managed MemoryChunk.
      60                 :             :  *
      61                 :             :  * MemoryChunkIsExternal:
      62                 :             :  *              Determine if the given MemoryChunk is externally managed, i.e.
      63                 :             :  *              MemoryChunkSetHdrMaskExternal() was called on the chunk.
      64                 :             :  *
      65                 :             :  * MemoryChunkGetValue:
      66                 :             :  *              For non-external chunks, return the stored 30-bit value as it was set
      67                 :             :  *              in the call to MemoryChunkSetHdrMask().
      68                 :             :  *
      69                 :             :  * MemoryChunkGetBlock:
      70                 :             :  *              For non-external chunks, return a pointer to the block as it was set
      71                 :             :  *              in the call to MemoryChunkSetHdrMask().
      72                 :             :  *
      73                 :             :  * Also exports:
      74                 :             :  *              MEMORYCHUNK_MAX_VALUE
      75                 :             :  *              MEMORYCHUNK_MAX_BLOCKOFFSET
      76                 :             :  *              PointerGetMemoryChunk
      77                 :             :  *              MemoryChunkGetPointer
      78                 :             :  *
      79                 :             :  * Portions Copyright (c) 2022-2026, PostgreSQL Global Development Group
      80                 :             :  * Portions Copyright (c) 1994, Regents of the University of California
      81                 :             :  *
      82                 :             :  * src/include/utils/memutils_memorychunk.h
      83                 :             :  *
      84                 :             :  *-------------------------------------------------------------------------
      85                 :             :  */
      86                 :             : 
      87                 :             : #ifndef MEMUTILS_MEMORYCHUNK_H
      88                 :             : #define MEMUTILS_MEMORYCHUNK_H
      89                 :             : 
      90                 :             : #include "utils/memutils_internal.h"
      91                 :             : 
      92                 :             :  /*
      93                 :             :   * The maximum allowed value that MemoryContexts can store in the value
      94                 :             :   * field.  Must be 1 less than a power of 2.
      95                 :             :   */
      96                 :             : #define MEMORYCHUNK_MAX_VALUE                   UINT64CONST(0x3FFFFFFF)
      97                 :             : 
      98                 :             : /*
      99                 :             :  * The maximum distance in bytes that a MemoryChunk can be offset from the
     100                 :             :  * block that is storing the chunk.  Must be 1 less than a power of 2.
     101                 :             :  */
     102                 :             : #define MEMORYCHUNK_MAX_BLOCKOFFSET             UINT64CONST(0x3FFFFFFF)
     103                 :             : 
     104                 :             : /*
     105                 :             :  * As above, but mask out the lowest-order (always zero) bit as this is shared
     106                 :             :  * with the MemoryChunkGetValue field.
     107                 :             :  */
     108                 :             : #define MEMORYCHUNK_BLOCKOFFSET_MASK    UINT64CONST(0x3FFFFFFE)
     109                 :             : 
     110                 :             : /* define the least significant base-0 bit of each portion of the hdrmask */
     111                 :             : #define MEMORYCHUNK_EXTERNAL_BASEBIT    MEMORY_CONTEXT_METHODID_BITS
     112                 :             : #define MEMORYCHUNK_VALUE_BASEBIT               (MEMORYCHUNK_EXTERNAL_BASEBIT + 1)
     113                 :             : #define MEMORYCHUNK_BLOCKOFFSET_BASEBIT (MEMORYCHUNK_VALUE_BASEBIT + 29)
     114                 :             : 
     115                 :             : /*
     116                 :             :  * A magic number for storing in the free bits of an external chunk.  This
     117                 :             :  * must mask out the bits used for storing the MemoryContextMethodID and the
     118                 :             :  * external bit.
     119                 :             :  */
     120                 :             : #define MEMORYCHUNK_MAGIC               (UINT64CONST(0xB1A8DB858EB6EFBA) >> \
     121                 :             :                                                                  MEMORYCHUNK_VALUE_BASEBIT << \
     122                 :             :                                                                  MEMORYCHUNK_VALUE_BASEBIT)
     123                 :             : 
     124                 :             : typedef struct MemoryChunk
     125                 :             : {
     126                 :             : #ifdef MEMORY_CONTEXT_CHECKING
     127                 :             :         Size            requested_size;
     128                 :             : #endif
     129                 :             : 
     130                 :             :         /* bitfield for storing details about the chunk */
     131                 :             :         uint64          hdrmask;                /* must be last */
     132                 :             : } MemoryChunk;
     133                 :             : 
     134                 :             : /* Get the MemoryChunk from the pointer */
     135                 :             : #define PointerGetMemoryChunk(p) \
     136                 :             :         ((MemoryChunk *) ((char *) (p) - sizeof(MemoryChunk)))
     137                 :             : /* Get the pointer from the MemoryChunk */
     138                 :             : #define MemoryChunkGetPointer(c) \
     139                 :             :         ((void *) ((char *) (c) + sizeof(MemoryChunk)))
     140                 :             : 
     141                 :             : /* private macros for making the inline functions below more simple */
     142                 :             : #define HdrMaskIsExternal(hdrmask) \
     143                 :             :         ((hdrmask) & (((uint64) 1) << MEMORYCHUNK_EXTERNAL_BASEBIT))
     144                 :             : #define HdrMaskGetValue(hdrmask) \
     145                 :             :         (((hdrmask) >> MEMORYCHUNK_VALUE_BASEBIT) & MEMORYCHUNK_MAX_VALUE)
     146                 :             : 
     147                 :             : /*
     148                 :             :  * Shift the block offset down to the 0th bit position and mask off the single
     149                 :             :  * bit that's shared with the MemoryChunkGetValue field.
     150                 :             :  */
     151                 :             : #define HdrMaskBlockOffset(hdrmask) \
     152                 :             :         (((hdrmask) >> MEMORYCHUNK_BLOCKOFFSET_BASEBIT) & MEMORYCHUNK_BLOCKOFFSET_MASK)
     153                 :             : 
     154                 :             : /* For external chunks only, check the magic number matches */
     155                 :             : #define HdrMaskCheckMagic(hdrmask) \
     156                 :             :         (MEMORYCHUNK_MAGIC == \
     157                 :             :          ((hdrmask) >> MEMORYCHUNK_VALUE_BASEBIT << MEMORYCHUNK_VALUE_BASEBIT))
     158                 :             : /*
     159                 :             :  * MemoryChunkSetHdrMask
     160                 :             :  *              Store the given 'block', 'chunk_size' and 'methodid' in the given
     161                 :             :  *              MemoryChunk.
     162                 :             :  *
     163                 :             :  * The number of bytes between 'block' and 'chunk' must be <=
     164                 :             :  * MEMORYCHUNK_MAX_BLOCKOFFSET.
     165                 :             :  * 'value' must be <= MEMORYCHUNK_MAX_VALUE.
     166                 :             :  * Both 'chunk' and 'block' must be MAXALIGNed pointers.
     167                 :             :  */
     168                 :             : static inline void
     169                 :    78760662 : MemoryChunkSetHdrMask(MemoryChunk *chunk, void *block,
     170                 :             :                                           Size value, MemoryContextMethodID methodid)
     171                 :             : {
     172                 :    78760662 :         Size            blockoffset = (char *) chunk - (char *) block;
     173                 :             : 
     174         [ +  - ]:    78760662 :         Assert((char *) chunk >= (char *) block);
     175         [ +  - ]:    78760662 :         Assert((blockoffset & MEMORYCHUNK_BLOCKOFFSET_MASK) == blockoffset);
     176         [ +  - ]:    78760662 :         Assert(value <= MEMORYCHUNK_MAX_VALUE);
     177         [ +  - ]:    78760662 :         Assert((int) methodid <= MEMORY_CONTEXT_METHODID_MASK);
     178                 :             : 
     179                 :   236281986 :         chunk->hdrmask = (((uint64) blockoffset) << MEMORYCHUNK_BLOCKOFFSET_BASEBIT) |
     180                 :   157521324 :                 (((uint64) value) << MEMORYCHUNK_VALUE_BASEBIT) |
     181                 :    78760662 :                 methodid;
     182                 :    78760662 : }
     183                 :             : 
     184                 :             : /*
     185                 :             :  * MemoryChunkSetHdrMaskExternal
     186                 :             :  *              Set 'chunk' as an externally managed chunk.  Here we only record the
     187                 :             :  *              MemoryContextMethodID and set the external chunk bit.
     188                 :             :  */
     189                 :             : static inline void
     190                 :     1576267 : MemoryChunkSetHdrMaskExternal(MemoryChunk *chunk,
     191                 :             :                                                           MemoryContextMethodID methodid)
     192                 :             : {
     193         [ +  - ]:     1576267 :         Assert((int) methodid <= MEMORY_CONTEXT_METHODID_MASK);
     194                 :             : 
     195                 :     1576267 :         chunk->hdrmask = MEMORYCHUNK_MAGIC | (((uint64) 1) << MEMORYCHUNK_EXTERNAL_BASEBIT) |
     196                 :     1576267 :                 methodid;
     197                 :     1576267 : }
     198                 :             : 
     199                 :             : /*
     200                 :             :  * MemoryChunkIsExternal
     201                 :             :  *              Return true if 'chunk' is marked as external.
     202                 :             :  */
     203                 :             : static inline bool
     204                 :   533325695 : MemoryChunkIsExternal(MemoryChunk *chunk)
     205                 :             : {
     206                 :             :         /*
     207                 :             :          * External chunks should always store MEMORYCHUNK_MAGIC in the upper
     208                 :             :          * portion of the hdrmask, check that nothing has stomped on that.
     209                 :             :          */
     210   [ +  +  +  - ]:   533325695 :         Assert(!HdrMaskIsExternal(chunk->hdrmask) ||
     211                 :             :                    HdrMaskCheckMagic(chunk->hdrmask));
     212                 :             : 
     213                 :   533325695 :         return HdrMaskIsExternal(chunk->hdrmask);
     214                 :             : }
     215                 :             : 
     216                 :             : /*
     217                 :             :  * MemoryChunkGetValue
     218                 :             :  *              For non-external chunks, returns the value field as it was set in
     219                 :             :  *              MemoryChunkSetHdrMask.
     220                 :             :  */
     221                 :             : static inline Size
     222                 :   568623488 : MemoryChunkGetValue(MemoryChunk *chunk)
     223                 :             : {
     224         [ +  - ]:   568623488 :         Assert(!HdrMaskIsExternal(chunk->hdrmask));
     225                 :             : 
     226                 :   568623488 :         return HdrMaskGetValue(chunk->hdrmask);
     227                 :             : }
     228                 :             : 
     229                 :             : /*
     230                 :             :  * MemoryChunkGetBlock
     231                 :             :  *              For non-external chunks, returns the pointer to the block as was set
     232                 :             :  *              in MemoryChunkSetHdrMask.
     233                 :             :  */
     234                 :             : static inline void *
     235                 :   526271655 : MemoryChunkGetBlock(MemoryChunk *chunk)
     236                 :             : {
     237         [ +  - ]:   526271655 :         Assert(!HdrMaskIsExternal(chunk->hdrmask));
     238                 :             : 
     239                 :   526271655 :         return (void *) ((char *) chunk - HdrMaskBlockOffset(chunk->hdrmask));
     240                 :             : }
     241                 :             : 
     242                 :             : /* cleanup all internal definitions */
     243                 :             : #undef MEMORYCHUNK_BLOCKOFFSET_MASK
     244                 :             : #undef MEMORYCHUNK_EXTERNAL_BASEBIT
     245                 :             : #undef MEMORYCHUNK_VALUE_BASEBIT
     246                 :             : #undef MEMORYCHUNK_BLOCKOFFSET_BASEBIT
     247                 :             : #undef MEMORYCHUNK_MAGIC
     248                 :             : #undef HdrMaskIsExternal
     249                 :             : #undef HdrMaskGetValue
     250                 :             : #undef HdrMaskBlockOffset
     251                 :             : #undef HdrMaskCheckMagic
     252                 :             : 
     253                 :             : #endif                                                  /* MEMUTILS_MEMORYCHUNK_H */
        

Generated by: LCOV version 2.3.2-1