Age Owner TLA 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 3-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. 3-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 MemoryContext 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 : * In some cases, for example when memory allocations become large, it's 38 : * possible fields 3 and 4 above are not large enough to store the values 39 : * required for the chunk. In this case, the MemoryContext can choose to mark 40 : * the chunk as "external" by calling the MemoryChunkSetExternal() function. 41 : * When this is done, fields 3 and 4 are unavailable for use by the 42 : * MemoryContext and it's up to the MemoryContext itself to devise its own 43 : * method for getting the reference to the block. 44 : * 45 : * Interface: 46 : * 47 : * MemoryChunkSetHdrMask: 48 : * Used to set up a non-external MemoryChunk. 49 : * 50 : * MemoryChunkSetHdrMaskExternal: 51 : * Used to set up an externally managed MemoryChunk. 52 : * 53 : * MemoryChunkIsExternal: 54 : * Determine if the given MemoryChunk is externally managed, i.e. 55 : * MemoryChunkSetHdrMaskExternal() was called on the chunk. 56 : * 57 : * MemoryChunkGetValue: 58 : * For non-external chunks, return the stored 30-bit value as it was set 59 : * in the call to MemoryChunkSetHdrMask(). 60 : * 61 : * MemoryChunkGetBlock: 62 : * For non-external chunks, return a pointer to the block as it was set 63 : * in the call to MemoryChunkSetHdrMask(). 64 : * 65 : * Also exports: 66 : * MEMORYCHUNK_MAX_VALUE 67 : * MEMORYCHUNK_MAX_BLOCKOFFSET 68 : * PointerGetMemoryChunk 69 : * MemoryChunkGetPointer 70 : * 71 : * Portions Copyright (c) 2022-2023, PostgreSQL Global Development Group 72 : * Portions Copyright (c) 1994, Regents of the University of California 73 : * 74 : * src/include/utils/memutils_memorychunk.h 75 : * 76 : *------------------------------------------------------------------------- 77 : */ 78 : 79 : #ifndef MEMUTILS_MEMORYCHUNK_H 80 : #define MEMUTILS_MEMORYCHUNK_H 81 : 82 : #include "utils/memutils_internal.h" 83 : 84 : /* 85 : * The maximum allowed value that MemoryContexts can store in the value 86 : * field. Must be 1 less than a power of 2. 87 : */ 88 : #define MEMORYCHUNK_MAX_VALUE UINT64CONST(0x3FFFFFFF) 89 : 90 : /* 91 : * The maximum distance in bytes that a MemoryChunk can be offset from the 92 : * block that is storing the chunk. Must be 1 less than a power of 2. 93 : */ 94 : #define MEMORYCHUNK_MAX_BLOCKOFFSET UINT64CONST(0x3FFFFFFF) 95 : 96 : /* define the least significant base-0 bit of each portion of the hdrmask */ 97 : #define MEMORYCHUNK_EXTERNAL_BASEBIT MEMORY_CONTEXT_METHODID_BITS 98 : #define MEMORYCHUNK_VALUE_BASEBIT (MEMORYCHUNK_EXTERNAL_BASEBIT + 1) 99 : #define MEMORYCHUNK_BLOCKOFFSET_BASEBIT (MEMORYCHUNK_VALUE_BASEBIT + 30) 100 : 101 : /* 102 : * A magic number for storing in the free bits of an external chunk. This 103 : * must mask out the bits used for storing the MemoryContextMethodID and the 104 : * external bit. 105 : */ 106 : #define MEMORYCHUNK_MAGIC (UINT64CONST(0xB1A8DB858EB6EFBA) >> \ 107 : MEMORYCHUNK_VALUE_BASEBIT << \ 108 : MEMORYCHUNK_VALUE_BASEBIT) 109 : 110 : typedef struct MemoryChunk 111 : { 112 : #ifdef MEMORY_CONTEXT_CHECKING 113 : Size requested_size; 114 : #endif 115 : 116 : /* bitfield for storing details about the chunk */ 117 : uint64 hdrmask; /* must be last */ 118 : } MemoryChunk; 119 : 120 : /* Get the MemoryChunk from the pointer */ 121 : #define PointerGetMemoryChunk(p) \ 122 : ((MemoryChunk *) ((char *) (p) - sizeof(MemoryChunk))) 123 : /* Get the pointer from the MemoryChunk */ 124 : #define MemoryChunkGetPointer(c) \ 125 : ((void *) ((char *) (c) + sizeof(MemoryChunk))) 126 : 127 : /* private macros for making the inline functions below more simple */ 128 : #define HdrMaskIsExternal(hdrmask) \ 129 : ((hdrmask) & (((uint64) 1) << MEMORYCHUNK_EXTERNAL_BASEBIT)) 130 : #define HdrMaskGetValue(hdrmask) \ 131 : (((hdrmask) >> MEMORYCHUNK_VALUE_BASEBIT) & MEMORYCHUNK_MAX_VALUE) 132 : 133 : /* 134 : * We should have used up all the bits here, so the compiler is likely to 135 : * optimize out the & MEMORYCHUNK_MAX_BLOCKOFFSET. 136 : */ 137 : #define HdrMaskBlockOffset(hdrmask) \ 138 : (((hdrmask) >> MEMORYCHUNK_BLOCKOFFSET_BASEBIT) & MEMORYCHUNK_MAX_BLOCKOFFSET) 139 : 140 : /* For external chunks only, check the magic number matches */ 141 : #define HdrMaskCheckMagic(hdrmask) \ 142 : (MEMORYCHUNK_MAGIC == \ 143 : ((hdrmask) >> MEMORYCHUNK_VALUE_BASEBIT << MEMORYCHUNK_VALUE_BASEBIT)) 144 : /* 145 : * MemoryChunkSetHdrMask 146 : * Store the given 'block', 'chunk_size' and 'methodid' in the given 147 : * MemoryChunk. 148 : * 149 : * The number of bytes between 'block' and 'chunk' must be <= 150 : * MEMORYCHUNK_MAX_BLOCKOFFSET. 151 : * 'value' must be <= MEMORYCHUNK_MAX_VALUE. 152 : */ 153 : static inline void 223 drowley 154 GNC 417962095 : MemoryChunkSetHdrMask(MemoryChunk *chunk, void *block, 155 : Size value, MemoryContextMethodID methodid) 156 : { 157 417962095 : Size blockoffset = (char *) chunk - (char *) block; 158 : 108 159 417962095 : Assert((char *) chunk >= (char *) block); 223 160 417962095 : Assert(blockoffset <= MEMORYCHUNK_MAX_BLOCKOFFSET); 161 417962095 : Assert(value <= MEMORYCHUNK_MAX_VALUE); 221 162 417962095 : Assert((int) methodid <= MEMORY_CONTEXT_METHODID_MASK); 163 : 223 164 417962095 : chunk->hdrmask = (((uint64) blockoffset) << MEMORYCHUNK_BLOCKOFFSET_BASEBIT) | 165 417962095 : (((uint64) value) << MEMORYCHUNK_VALUE_BASEBIT) | 166 : methodid; 167 417962095 : } 168 : 169 : /* 170 : * MemoryChunkSetHdrMaskExternal 171 : * Set 'chunk' as an externally managed chunk. Here we only record the 172 : * MemoryContextMethodID and set the external chunk bit. 173 : */ 174 : static inline void 175 11334463 : MemoryChunkSetHdrMaskExternal(MemoryChunk *chunk, 176 : MemoryContextMethodID methodid) 177 : { 221 178 11334463 : Assert((int) methodid <= MEMORY_CONTEXT_METHODID_MASK); 179 : 223 180 11334463 : chunk->hdrmask = MEMORYCHUNK_MAGIC | (((uint64) 1) << MEMORYCHUNK_EXTERNAL_BASEBIT) | 181 : methodid; 182 11334463 : } 183 : 184 : /* 185 : * MemoryChunkIsExternal 186 : * Return true if 'chunk' is marked as external. 187 : */ 188 : static inline bool 189 4127461249 : MemoryChunkIsExternal(MemoryChunk *chunk) 190 : { 191 : /* 192 : * External chunks should always store MEMORYCHUNK_MAGIC in the upper 193 : * portion of the hdrmask, check that nothing has stomped on that. 194 : */ 195 4127461249 : Assert(!HdrMaskIsExternal(chunk->hdrmask) || 196 : HdrMaskCheckMagic(chunk->hdrmask)); 197 : 198 4127461249 : return HdrMaskIsExternal(chunk->hdrmask); 199 : } 200 : 201 : /* 202 : * MemoryChunkGetValue 203 : * For non-external chunks, returns the value field as it was set in 204 : * MemoryChunkSetHdrMask. 205 : */ 206 : static inline Size 207 4329954035 : MemoryChunkGetValue(MemoryChunk *chunk) 208 : { 209 4329954035 : Assert(!HdrMaskIsExternal(chunk->hdrmask)); 210 : 211 4329954035 : return HdrMaskGetValue(chunk->hdrmask); 212 : } 213 : 214 : /* 215 : * MemoryChunkGetBlock 216 : * For non-external chunks, returns the pointer to the block as was set 217 : * in MemoryChunkSetHdrMask. 218 : */ 219 : static inline void * 220 4073405479 : MemoryChunkGetBlock(MemoryChunk *chunk) 221 : { 222 4073405479 : Assert(!HdrMaskIsExternal(chunk->hdrmask)); 223 : 224 4073405479 : return (void *) ((char *) chunk - HdrMaskBlockOffset(chunk->hdrmask)); 225 : } 226 : 227 : /* cleanup all internal definitions */ 228 : #undef MEMORYCHUNK_EXTERNAL_BASEBIT 229 : #undef MEMORYCHUNK_VALUE_BASEBIT 230 : #undef MEMORYCHUNK_BLOCKOFFSET_BASEBIT 231 : #undef MEMORYCHUNK_MAGIC 232 : #undef HdrMaskIsExternal 233 : #undef HdrMaskGetValue 234 : #undef HdrMaskBlockOffset 235 : #undef HdrMaskCheckMagic 236 : 237 : #endif /* MEMUTILS_MEMORYCHUNK_H */