// // Z_Malloc // // You can pass a NULL user if the tag is < PU_PURGELEVEL. // void *(Z_Malloc)(size_t size, int tag, void **user, const char *file, int line) { memblock_t *block; byte *ret; DEBUG_CHECKHEAP(); Z_IDCheckNB(IDBOOL(tag >= PU_PURGELEVEL && !user), "Z_Malloc: an owner is required for purgable blocks", file, line); if(!size) return user ? *user = NULL : NULL; // malloc(0) returns NULL if(!(block = (memblock_t *)(malloc(size + header_size)))) { if(blockbytag[PU_CACHE]) { Z_FreeTags(PU_CACHE, PU_CACHE); block = (memblock_t *)(malloc(size + header_size)); } } if(!block) { I_FatalError(I_ERR_KILL, "Z_Malloc: Failure trying to allocate %u bytes\n" "Source: %s:%d\n", (unsigned int)size, file, line); } block->size = size; if((block->next = blockbytag[tag])) block->next->prev = &block->next; blockbytag[tag] = block; block->prev = &blockbytag[tag]; INSTRUMENT(memorybytag[tag] += block->size); INSTRUMENT(block->file = file); INSTRUMENT(block->line = line); IDCHECK(block->id = ZONEID); // signature required in block header block->tag = tag; // tag block->user = user; // user ret = ((byte *) block + header_size); if(user) // if there is a user *user = ret; // set user to point to new block // scramble memory -- weed out any bugs SCRAMBLER(ret, size); Z_LogPrintf("* %p = Z_Malloc(size=%lu, tag=%d, user=%p, source=%s:%d)\n", ret, size, tag, user, file, line); return ret; }
// // Z_FreeAlloca // // haleyjd 12/06/06: Frees all blocks allocated with Z_Alloca. // void Z_FreeAlloca(void) { memblock_t *block = blockbytag[PU_AUTO]; if(!block) return; Z_LogPuts("* Freeing alloca blocks\n"); blockbytag[PU_AUTO] = NULL; while(block) { memblock_t *next = block->next; Z_IDCheckNB(IDBOOL(block->id != ZONEID), "Z_FreeAlloca: Freed a tag without ZONEID", __FILE__, __LINE__); Z_Free((byte *)block + header_size); block = next; // Advance to next block } }
// // Z_Malloc // // You can pass a NULL user if the tag is < PU_PURGELEVEL. // void *(Z_Malloc)(size_t size, int tag, void **user, __string file, int line) { register memblock_t __near *block, *start; INSTRUMENT(register size_t size_orig = size); // davidph 12/10/12: If zone not initialized, do so now. if(!zone) (Z_Init)(file, line); DEBUG_CHECKHEAP(); Z_IDCheckNB(IDBOOL(tag >= PU_PURGELEVEL && !user), "Z_Malloc: an owner is required for purgable blocks", file, line); if(!size) return user ? *user = NULL : NULL; // malloc(0) returns NULL size = (size+CHUNK_SIZE-1) & ~(CHUNK_SIZE-1); // round to chunk size block = rover; if(block->prev->tag == PU_FREE) block = block->prev; start = block; // haleyjd 01/01/01 (happy new year!): // the first if() inside the loop below contains cph's memory // purging efficiency fix do { // Free purgable blocks; replacement is roughly FIFO if(block->tag >= PU_PURGELEVEL) { start = block->prev; Z_Free((char __near *)block + HEADER_SIZE); // cph - If start->next == block, we did not merge with the previous // If !=, we did, so we continue from start. // Important: we've reset start! if(start->next == block) start = start->next; else block = start; } if(block->tag == PU_FREE && block->size >= size) // First-fit { size_t extra = block->size - size; if(extra >= MIN_BLOCK_SPLIT + HEADER_SIZE) { memblock_t __near *newb = (memblock_t __near *)((char __near *)block + HEADER_SIZE + size); (newb->next = block->next)->prev = newb; (newb->prev = block)->next = newb; // Split up block block->size = size; newb->size = extra - HEADER_SIZE; newb->tag = PU_FREE; INSTRUMENT(inactive_memory += HEADER_SIZE); INSTRUMENT(free_memory -= HEADER_SIZE); } rover = block->next; // set roving pointer for next search #ifdef INSTRUMENTED inactive_memory += block->extra = block->size - size_orig; if(tag >= PU_PURGELEVEL) purgable_memory += size_orig; else active_memory += size_orig; free_memory -= block->size; #endif INSTRUMENT(block->file = file); INSTRUMENT(block->line = line); IDCHECK(block->id = ZONEID);// signature required in block header block->tag = tag; // tag block->user = user; // user block = BlockToVoid(block); if(user) // if there is a user *user = block; // set user to point to new block Z_PrintStats(); // print memory allocation stats // scramble memory -- weed out any bugs SCRAMBLER(block, size); Z_LogPrintf("* %p = Z_Malloc(size=%u, tag=%d, user=%p, source=%s:%d)\n", block, size, tag, user, file, line); return block; } } while((block = block->next) != start); // detect cycles as failure zonef("Z_Malloc: Failure trying to allocate %u bytes\nSource: %s:%d\n", size, file, line); abort(); }