📄 aset.c
字号:
/* Test for someone scribbling on unused space in chunk */ if (chunk->requested_size < chunk->size) if (((char *) pointer)[chunk->requested_size] != 0x7E) elog(WARNING, "detected write past chunk end in %s %p", set->header.name, chunk);#endif if (chunk->size > ALLOC_CHUNK_LIMIT) { /* * Big chunks are certain to have been allocated as single-chunk * blocks. Find the containing block and return it to malloc(). */ AllocBlock block = set->blocks; AllocBlock prevblock = NULL; while (block != NULL) { if (chunk == (AllocChunk) (((char *) block) + ALLOC_BLOCKHDRSZ)) break; prevblock = block; block = block->next; } if (block == NULL) elog(ERROR, "could not find block containing chunk %p", chunk); /* let's just make sure chunk is the only one in the block */ Assert(block->freeptr == ((char *) block) + (chunk->size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ)); /* OK, remove block from aset's list and free it */ if (prevblock == NULL) set->blocks = block->next; else prevblock->next = block->next;#ifdef CLOBBER_FREED_MEMORY /* Wipe freed memory for debugging purposes */ memset(block, 0x7F, block->freeptr - ((char *) block));#endif free(block); } else { /* Normal case, put the chunk into appropriate freelist */ int fidx = AllocSetFreeIndex(chunk->size); chunk->aset = (void *) set->freelist[fidx];#ifdef CLOBBER_FREED_MEMORY /* Wipe freed memory for debugging purposes */ memset(pointer, 0x7F, chunk->size);#endif#ifdef MEMORY_CONTEXT_CHECKING /* Reset requested_size to 0 in chunks that are on freelist */ chunk->requested_size = 0;#endif set->freelist[fidx] = chunk; }}/* * AllocSetRealloc * Returns new pointer to allocated memory of given size; this memory * is added to the set. Memory associated with given pointer is copied * into the new memory, and the old memory is freed. */static void *AllocSetRealloc(MemoryContext context, void *pointer, Size size){ AllocSet set = (AllocSet) context; AllocChunk chunk = AllocPointerGetChunk(pointer); Size oldsize = chunk->size;#ifdef MEMORY_CONTEXT_CHECKING /* Test for someone scribbling on unused space in chunk */ if (chunk->requested_size < oldsize) if (((char *) pointer)[chunk->requested_size] != 0x7E) elog(WARNING, "detected write past chunk end in %s %p", set->header.name, chunk);#endif /* isReset must be false already */ Assert(!set->isReset); /* * Chunk sizes are aligned to power of 2 in AllocSetAlloc(). Maybe the * allocated area already is >= the new size. (In particular, we always * fall out here if the requested size is a decrease.) */ if (oldsize >= size) {#ifdef MEMORY_CONTEXT_CHECKING chunk->requested_size = size; /* set mark to catch clobber of "unused" space */ if (size < oldsize) ((char *) pointer)[size] = 0x7E;#endif return pointer; } if (oldsize > ALLOC_CHUNK_LIMIT) { /* * The chunk must been allocated as a single-chunk block. Find the * containing block and use realloc() to make it bigger with minimum * space wastage. */ AllocBlock block = set->blocks; AllocBlock prevblock = NULL; Size chksize; Size blksize; while (block != NULL) { if (chunk == (AllocChunk) (((char *) block) + ALLOC_BLOCKHDRSZ)) break; prevblock = block; block = block->next; } if (block == NULL) elog(ERROR, "could not find block containing chunk %p", chunk); /* let's just make sure chunk is the only one in the block */ Assert(block->freeptr == ((char *) block) + (chunk->size + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ)); /* Do the realloc */ chksize = MAXALIGN(size); blksize = chksize + ALLOC_BLOCKHDRSZ + ALLOC_CHUNKHDRSZ; block = (AllocBlock) realloc(block, blksize); if (block == NULL) { MemoryContextStats(TopMemoryContext); ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"), errdetail("Failed on request of size %lu.", (unsigned long) size))); } block->freeptr = block->endptr = ((char *) block) + blksize; /* Update pointers since block has likely been moved */ chunk = (AllocChunk) (((char *) block) + ALLOC_BLOCKHDRSZ); if (prevblock == NULL) set->blocks = block; else prevblock->next = block; chunk->size = chksize;#ifdef MEMORY_CONTEXT_CHECKING chunk->requested_size = size; /* set mark to catch clobber of "unused" space */ if (size < chunk->size) ((char *) AllocChunkGetPointer(chunk))[size] = 0x7E;#endif return AllocChunkGetPointer(chunk); } else { /* * Small-chunk case. If the chunk is the last one in its block, there * might be enough free space after it that we can just enlarge the * chunk in-place. It's relatively painful to find the containing * block in the general case, but we can detect last-ness quite * cheaply for the typical case where the chunk is in the active * (topmost) allocation block. (At least with the regression tests * and code as of 1/2001, realloc'ing the last chunk of a non-topmost * block hardly ever happens, so it's not worth scanning the block * list to catch that case.) * * NOTE: must be careful not to create a chunk of a size that * AllocSetAlloc would not create, else we'll get confused later. */ AllocPointer newPointer; if (size <= ALLOC_CHUNK_LIMIT) { AllocBlock block = set->blocks; char *chunk_end; chunk_end = (char *) chunk + (oldsize + ALLOC_CHUNKHDRSZ); if (chunk_end == block->freeptr) { /* OK, it's last in block ... is there room? */ Size freespace = block->endptr - block->freeptr; int fidx; Size newsize; Size delta; fidx = AllocSetFreeIndex(size); newsize = 1 << (fidx + ALLOC_MINBITS); Assert(newsize >= oldsize); delta = newsize - oldsize; if (freespace >= delta) { /* Yes, so just enlarge the chunk. */ block->freeptr += delta; chunk->size += delta;#ifdef MEMORY_CONTEXT_CHECKING chunk->requested_size = size; /* set mark to catch clobber of "unused" space */ if (size < chunk->size) ((char *) pointer)[size] = 0x7E;#endif return pointer; } } } /* Normal small-chunk case: just do it by brute force. */ /* allocate new chunk */ newPointer = AllocSetAlloc((MemoryContext) set, size); /* transfer existing data (certain to fit) */ memcpy(newPointer, pointer, oldsize); /* free old chunk */ AllocSetFree((MemoryContext) set, pointer); return newPointer; }}/* * AllocSetGetChunkSpace * Given a currently-allocated chunk, determine the total space * it occupies (including all memory-allocation overhead). */static SizeAllocSetGetChunkSpace(MemoryContext context, void *pointer){ AllocChunk chunk = AllocPointerGetChunk(pointer); return chunk->size + ALLOC_CHUNKHDRSZ;}/* * AllocSetIsEmpty * Is an allocset empty of any allocated space? */static boolAllocSetIsEmpty(MemoryContext context){ AllocSet set = (AllocSet) context; /* * For now, we say "empty" only if the context is new or just reset. We * could examine the freelists to determine if all space has been freed, * but it's not really worth the trouble for present uses of this * functionality. */ if (set->isReset) return true; return false;}/* * AllocSetStats * Displays stats about memory consumption of an allocset. */static voidAllocSetStats(MemoryContext context){ AllocSet set = (AllocSet) context; long nblocks = 0; long nchunks = 0; long totalspace = 0; long freespace = 0; AllocBlock block; AllocChunk chunk; int fidx; for (block = set->blocks; block != NULL; block = block->next) { nblocks++; totalspace += block->endptr - ((char *) block); freespace += block->endptr - block->freeptr; } for (fidx = 0; fidx < ALLOCSET_NUM_FREELISTS; fidx++) { for (chunk = set->freelist[fidx]; chunk != NULL; chunk = (AllocChunk) chunk->aset) { nchunks++; freespace += chunk->size + ALLOC_CHUNKHDRSZ; } } fprintf(stderr, "%s: %ld total in %ld blocks; %ld free (%ld chunks); %ld used\n", set->header.name, totalspace, nblocks, freespace, nchunks, totalspace - freespace);}#ifdef MEMORY_CONTEXT_CHECKING/* * AllocSetCheck * Walk through chunks and check consistency of memory. * * NOTE: report errors as WARNING, *not* ERROR or FATAL. Otherwise you'll * find yourself in an infinite loop when trouble occurs, because this * routine will be entered again when elog cleanup tries to release memory! */static voidAllocSetCheck(MemoryContext context){ AllocSet set = (AllocSet) context; char *name = set->header.name; AllocBlock block; for (block = set->blocks; block != NULL; block = block->next) { char *bpoz = ((char *) block) + ALLOC_BLOCKHDRSZ; long blk_used = block->freeptr - bpoz; long blk_data = 0; long nchunks = 0; /* * Empty block - empty can be keeper-block only */ if (!blk_used) { if (set->keeper != block) elog(WARNING, "problem in alloc set %s: empty block %p", name, block); } /* * Chunk walker */ while (bpoz < block->freeptr) { AllocChunk chunk = (AllocChunk) bpoz; Size chsize, dsize; char *chdata_end; chsize = chunk->size; /* aligned chunk size */ dsize = chunk->requested_size; /* real data */ chdata_end = ((char *) chunk) + (ALLOC_CHUNKHDRSZ + dsize); /* * Check chunk size */ if (dsize > chsize) elog(WARNING, "problem in alloc set %s: req size > alloc size for chunk %p in block %p", name, chunk, block); if (chsize < (1 << ALLOC_MINBITS)) elog(WARNING, "problem in alloc set %s: bad size %lu for chunk %p in block %p", name, (unsigned long) chsize, chunk, block); /* single-chunk block? */ if (chsize > ALLOC_CHUNK_LIMIT && chsize + ALLOC_CHUNKHDRSZ != blk_used) elog(WARNING, "problem in alloc set %s: bad single-chunk %p in block %p", name, chunk, block); /* * If chunk is allocated, check for correct aset pointer. (If it's * free, the aset is the freelist pointer, which we can't check as * easily...) */ if (dsize > 0 && chunk->aset != (void *) set) elog(WARNING, "problem in alloc set %s: bogus aset link in block %p, chunk %p", name, block, chunk); /* * Check for overwrite of "unallocated" space in chunk */ if (dsize > 0 && dsize < chsize && *chdata_end != 0x7E) elog(WARNING, "problem in alloc set %s: detected write past chunk end in block %p, chunk %p", name, block, chunk); blk_data += chsize; nchunks++; bpoz += ALLOC_CHUNKHDRSZ + chsize; } if ((blk_data + (nchunks * ALLOC_CHUNKHDRSZ)) != blk_used) elog(WARNING, "problem in alloc set %s: found inconsistent memory block %p", name, block); }}#endif /* MEMORY_CONTEXT_CHECKING */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -