mirror of
https://github.com/fabiangreffrath/woof.git
synced 2025-09-22 03:12:00 -04:00
simplify and adapt z_zone.c to DSDA-Doom (#620)
* simplify and adapt z_zone.c to DSDA-Doom * remove the INSTRUMENTED macro * remove Z_Init() and Z_CheckHeap() * remove PU_LOCKED * eplicitly free all cached memory blocks on level setup * assure proper pointer alignment * fix headers * reorder struct memblock, decrease padding * add back historic changelogs
This commit is contained in:
parent
5cbd8e49d1
commit
0e6e346b32
@ -48,7 +48,6 @@ if(NOT WIN32)
|
||||
endif()
|
||||
|
||||
# Toggle-able defines added at compile-time.
|
||||
option("${PROJECT_NAME}_INSTRUMENTED" "Enable memory allocation statistics" OFF)
|
||||
option("${PROJECT_NAME}_RANGECHECK" "Enable bounds-checking of performance-sensitive functions" ON)
|
||||
option("${PROJECT_NAME}_STRICT" "Prefer original MBF code paths over demo compatiblity with PrBoom+" OFF)
|
||||
|
||||
|
@ -178,8 +178,6 @@ static void MissionSet(void)
|
||||
|
||||
void D_DoomMain(void)
|
||||
{
|
||||
Z_Init();
|
||||
|
||||
//SetupMission(MissionSet);
|
||||
MissionSet();
|
||||
|
||||
|
@ -176,9 +176,6 @@ endif()
|
||||
#
|
||||
# Our defines are not namespaced, so we pass them at compile-time instead of
|
||||
# using config.h.
|
||||
if("${${PROJECT_NAME}_INSTRUMENTED}")
|
||||
target_compile_definitions(woof PRIVATE INSTRUMENTED)
|
||||
endif()
|
||||
if("${${PROJECT_NAME}_RANGECHECK}")
|
||||
target_compile_definitions(woof PRIVATE RANGECHECK)
|
||||
endif()
|
||||
|
@ -1648,8 +1648,6 @@ void D_DoomMain(void)
|
||||
|
||||
setbuf(stdout,NULL);
|
||||
|
||||
Z_Init(); // 1/18/98 killough: start up memory stuff first
|
||||
|
||||
I_AtExitPrio(I_QuitFirst, true, "I_QuitFirst", exit_priority_first);
|
||||
I_AtExitPrio(I_QuitLast, false, "I_QuitLast", exit_priority_last);
|
||||
I_AtExitPrio(I_Quit, true, "I_Quit", exit_priority_last);
|
||||
|
11
src/g_game.c
11
src/g_game.c
@ -716,7 +716,6 @@ static void G_DoLoadLevel(void)
|
||||
P_SetupLevel (gameepisode, gamemap, 0, gameskill);
|
||||
displayplayer = consoleplayer; // view the guy you are playing
|
||||
gameaction = ga_nothing;
|
||||
Z_CheckHeap();
|
||||
|
||||
// clear cmd building stuff
|
||||
memset (gamekeydown, 0, sizeof(gamekeydown));
|
||||
@ -1759,17 +1758,11 @@ static void G_DoSaveGame(void)
|
||||
// killough 11/98: save revenant tracer state
|
||||
*save_p++ = (gametic-basetic) & 255;
|
||||
|
||||
// killough 3/22/98: add Z_CheckHeap after each call to ensure consistency
|
||||
Z_CheckHeap();
|
||||
P_ArchivePlayers();
|
||||
Z_CheckHeap();
|
||||
P_ArchiveWorld();
|
||||
Z_CheckHeap();
|
||||
P_ArchiveThinkers();
|
||||
Z_CheckHeap();
|
||||
P_ArchiveSpecials();
|
||||
P_ArchiveRNG(); // killough 1/18/98: save RNG information
|
||||
Z_CheckHeap();
|
||||
P_ArchiveMap(); // killough 1/22/98: save automap information
|
||||
|
||||
*save_p++ = 0xe6; // consistancy marker
|
||||
@ -1792,8 +1785,6 @@ static void G_DoSaveGame(void)
|
||||
|
||||
length = save_p - savebuffer;
|
||||
|
||||
Z_CheckHeap();
|
||||
|
||||
if (!M_WriteFile(name, savebuffer, length))
|
||||
dprintf("%s", errno ? strerror(errno) : "Could not save game: Error unknown");
|
||||
else
|
||||
@ -1969,8 +1960,6 @@ static void G_DoLoadGame(void)
|
||||
// draw the pattern into the back screen
|
||||
R_FillBackScreen();
|
||||
|
||||
Z_CheckHeap();
|
||||
|
||||
// killough 12/98: support -recordfrom and -loadgame -playdemo
|
||||
if (!command_loadgame)
|
||||
singledemo = false; // Clear singledemo flag if loading from menu
|
||||
|
@ -1669,8 +1669,6 @@ void I_ResetScreen(void)
|
||||
WI_DrawBackground();
|
||||
V_CopyRect(0, 0, 1, SCREENWIDTH, SCREENHEIGHT, 0, 0, 0);
|
||||
}
|
||||
|
||||
Z_CheckHeap();
|
||||
|
||||
M_ResetSetupMenuVideo();
|
||||
}
|
||||
@ -1705,8 +1703,6 @@ void I_InitGraphics(void)
|
||||
|
||||
I_InitGraphicsMode(); // killough 10/98
|
||||
|
||||
Z_CheckHeap();
|
||||
|
||||
M_ResetSetupMenuVideo();
|
||||
}
|
||||
|
||||
|
@ -84,10 +84,6 @@ static void cheat_rate();
|
||||
static void cheat_buddha();
|
||||
static void cheat_spechits();
|
||||
|
||||
#ifdef INSTRUMENTED
|
||||
static void cheat_printstats(); // killough 8/23/98
|
||||
#endif
|
||||
|
||||
static void cheat_autoaim(); // killough 7/19/98
|
||||
static void cheat_tst();
|
||||
static void cheat_showfps(); // [FG] FPS counter widget
|
||||
@ -274,11 +270,6 @@ struct cheat_s cheat[] = {
|
||||
{"nc", NULL, not_net | not_demo | beta_only,
|
||||
cheat_noclip },
|
||||
|
||||
#ifdef INSTRUMENTED
|
||||
{"stat", NULL, always,
|
||||
cheat_printstats},
|
||||
#endif
|
||||
|
||||
// [FG] FPS counter widget
|
||||
{"showfps", NULL, always,
|
||||
cheat_showfps},
|
||||
@ -288,14 +279,6 @@ struct cheat_s cheat[] = {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifdef INSTRUMENTED
|
||||
static void cheat_printstats() // killough 8/23/98
|
||||
{
|
||||
if (!(printstats=!printstats))
|
||||
plyr->message = "Memory stats off";
|
||||
}
|
||||
#endif
|
||||
|
||||
// [FG] FPS counter widget
|
||||
static void cheat_showfps()
|
||||
{
|
||||
|
@ -717,8 +717,6 @@ int main(int argc, char *argv[])
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
Z_Init();
|
||||
|
||||
infile_len = M_ReadFile(argv[1], &infile);
|
||||
|
||||
src = mem_fopen_read(infile, infile_len);
|
||||
|
@ -1528,7 +1528,8 @@ void P_SetupLevel(int episode, int map, int playermask, skill_t skill)
|
||||
// Make sure all sounds are stopped before Z_FreeTags.
|
||||
S_Start();
|
||||
|
||||
Z_FreeTags(PU_LEVEL, PU_PURGELEVEL-1);
|
||||
Z_FreeTag(PU_LEVEL);
|
||||
Z_FreeTag(PU_CACHE);
|
||||
|
||||
P_InitThinkers();
|
||||
|
||||
|
724
src/z_zone.c
724
src/z_zone.c
@ -35,670 +35,176 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "z_zone.h"
|
||||
#include "doomstat.h"
|
||||
#include "m_argv.h"
|
||||
|
||||
// Uncomment this to see real-time memory allocation
|
||||
// statistics, to and enable extra debugging features
|
||||
//#define INSTRUMENTED
|
||||
|
||||
// Uncomment this to exhaustively run memory checks
|
||||
// while the game is running (this is EXTREMELY slow).
|
||||
// Only useful if INSTRUMENTED is also defined.
|
||||
//#define CHECKHEAP
|
||||
|
||||
// Uncomment this to perform id checks on zone blocks,
|
||||
// to detect corrupted and illegally freed blocks
|
||||
#define ZONEIDCHECK
|
||||
|
||||
// Tunables
|
||||
|
||||
// Alignment of zone memory (benefit may be negated by HEADER_SIZE, CHUNK_SIZE)
|
||||
#define CACHE_ALIGN 32
|
||||
|
||||
// size of block header
|
||||
//#define HEADER_SIZE 32
|
||||
#include "i_system.h"
|
||||
|
||||
// Minimum chunk size at which blocks are allocated
|
||||
#define CHUNK_SIZE 32
|
||||
|
||||
// Minimum size a block must be to become part of a split
|
||||
#define MIN_BLOCK_SPLIT (1024)
|
||||
|
||||
// How much RAM to leave aside for other libraries
|
||||
#define LEAVE_ASIDE (128*1024)
|
||||
|
||||
// Minimum RAM machine is assumed to have
|
||||
#define MIN_RAM (7*1024*1024)
|
||||
|
||||
// [FG] allocate 64 MiB by default
|
||||
#define DEF_RAM (64*1024*1024)
|
||||
|
||||
// Amount to subtract when retrying failed attempts to allocate initial pool
|
||||
#define RETRY_AMOUNT (256*1024)
|
||||
#define CHUNK_SIZE sizeof(void *)
|
||||
|
||||
// signature for block header
|
||||
#define ZONEID 0x931d4a11
|
||||
|
||||
// Number of mallocs & frees kept in history buffer (must be a power of 2)
|
||||
#define ZONE_HISTORY 4
|
||||
|
||||
// End Tunables
|
||||
|
||||
typedef struct memblock {
|
||||
|
||||
#ifdef ZONEIDCHECK
|
||||
unsigned id;
|
||||
#endif
|
||||
|
||||
struct memblock *next,*prev;
|
||||
size_t size;
|
||||
void **user;
|
||||
unsigned char tag,vm;
|
||||
|
||||
#ifdef INSTRUMENTED
|
||||
unsigned short extra;
|
||||
const char *file;
|
||||
int line;
|
||||
#endif
|
||||
|
||||
unsigned id;
|
||||
int tag;
|
||||
} memblock_t;
|
||||
|
||||
/* size of block header
|
||||
* cph - base on sizeof(memblock_t), which can be larger than CHUNK_SIZE on
|
||||
* 64bit architectures */
|
||||
static const size_t HEADER_SIZE = (sizeof(memblock_t)+CHUNK_SIZE-1) & ~(CHUNK_SIZE-1);
|
||||
|
||||
static memblock_t *rover; // roving pointer to memory blocks
|
||||
static memblock_t *zone; // pointer to first block
|
||||
static memblock_t *zonebase; // pointer to entire zone memory
|
||||
static size_t zonebase_size; // zone memory allocated size
|
||||
static memblock_t *blockbytag[PU_MAX];
|
||||
|
||||
#ifdef INSTRUMENTED
|
||||
|
||||
// statistics for evaluating performance
|
||||
static size_t free_memory;
|
||||
static size_t active_memory;
|
||||
static size_t purgable_memory;
|
||||
static size_t inactive_memory;
|
||||
static size_t virtual_memory;
|
||||
|
||||
int printstats; // killough 8/23/98
|
||||
|
||||
void Z_PrintStats(void) // Print allocation statistics
|
||||
{
|
||||
if (printstats)
|
||||
{
|
||||
unsigned long total_memory = free_memory + active_memory +
|
||||
purgable_memory + inactive_memory +
|
||||
virtual_memory;
|
||||
double s = 100.0 / total_memory;
|
||||
|
||||
dprintf("%-5lu\t%6.01f%%\tstatic\n"
|
||||
"%-5lu\t%6.01f%%\tpurgable\n"
|
||||
"%-5lu\t%6.01f%%\tfree\n"
|
||||
"%-5lu\t%6.01f%%\tfragmentary\n"
|
||||
"%-5lu\t%6.01f%%\tvirtual\n"
|
||||
"%-5lu\t\ttotal\n",
|
||||
active_memory,
|
||||
active_memory*s,
|
||||
purgable_memory,
|
||||
purgable_memory*s,
|
||||
free_memory,
|
||||
free_memory*s,
|
||||
inactive_memory,
|
||||
inactive_memory*s,
|
||||
virtual_memory,
|
||||
virtual_memory*s,
|
||||
total_memory
|
||||
);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef INSTRUMENTED
|
||||
|
||||
// killough 4/26/98: Add history information
|
||||
|
||||
enum {malloc_history, free_history, NUM_HISTORY_TYPES};
|
||||
|
||||
static const char *file_history[NUM_HISTORY_TYPES][ZONE_HISTORY];
|
||||
static int line_history[NUM_HISTORY_TYPES][ZONE_HISTORY];
|
||||
static int history_index[NUM_HISTORY_TYPES];
|
||||
static const char *const desc[NUM_HISTORY_TYPES] = {"malloc()'s", "free()'s"};
|
||||
|
||||
void Z_DumpHistory(char *buf)
|
||||
{
|
||||
int i,j;
|
||||
char s[1024];
|
||||
strcat(buf,"\n");
|
||||
for (i=0;i<NUM_HISTORY_TYPES;i++)
|
||||
{
|
||||
sprintf(s,"\nLast several %s:\n\n", desc[i]);
|
||||
strcat(buf,s);
|
||||
for (j=0; j<ZONE_HISTORY; j++)
|
||||
{
|
||||
int k = (history_index[i]-j-1) & (ZONE_HISTORY-1);
|
||||
if (file_history[i][k])
|
||||
{
|
||||
sprintf(s, "File: %s, Line: %d\n", file_history[i][k],
|
||||
line_history[i][k]);
|
||||
strcat(buf,s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
void Z_DumpHistory(char *buf)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void Z_Close(void)
|
||||
{
|
||||
free(zonebase);
|
||||
zone = rover = zonebase = NULL;
|
||||
}
|
||||
|
||||
void Z_Init(void)
|
||||
{
|
||||
// haleyjd: -heapsize support
|
||||
int p, mb_size;
|
||||
size_t size = DEF_RAM; // [FG] allocate 32 MiB by default
|
||||
|
||||
p = M_CheckParm("-heapsize");
|
||||
|
||||
// [FG] support Chocolate Doom's -mb parameter
|
||||
if (!p)
|
||||
{
|
||||
p = M_CheckParm("-mb");
|
||||
}
|
||||
|
||||
if(p && ++p < myargc)
|
||||
{
|
||||
mb_size = atoi(myargv[p]);
|
||||
size = (size_t)(mb_size * 1024 * 1024);
|
||||
}
|
||||
|
||||
if (size < MIN_RAM) // If less than MIN_RAM, assume MIN_RAM anyway
|
||||
size = MIN_RAM;
|
||||
|
||||
size -= LEAVE_ASIDE; // Leave aside some for other libraries
|
||||
|
||||
assert(HEADER_SIZE >= sizeof(memblock_t) && MIN_RAM > LEAVE_ASIDE);
|
||||
|
||||
I_AtExitPrio(Z_Close, true, "Z_Close", exit_priority_verylast); // exit handler
|
||||
|
||||
size = (size+CHUNK_SIZE-1) & ~(CHUNK_SIZE-1); // round to chunk size
|
||||
|
||||
// Allocate the memory
|
||||
|
||||
while (!(zonebase=malloc(zonebase_size=size + HEADER_SIZE + CACHE_ALIGN)))
|
||||
if (size < (MIN_RAM-LEAVE_ASIDE < RETRY_AMOUNT ? RETRY_AMOUNT :
|
||||
MIN_RAM-LEAVE_ASIDE))
|
||||
I_Error("Z_Init: failed on allocation of %lu bytes",(unsigned long)
|
||||
zonebase_size);
|
||||
else
|
||||
size -= RETRY_AMOUNT;
|
||||
|
||||
// Align on cache boundary
|
||||
|
||||
zone = (memblock_t *) ((char *) zonebase + CACHE_ALIGN -
|
||||
((uintptr_t) zonebase & (CACHE_ALIGN-1)));
|
||||
|
||||
rover = zone; // Rover points to base of zone mem
|
||||
zone->next = zone->prev = zone; // Single node
|
||||
zone->size = size; // All memory in one block
|
||||
zone->tag = PU_FREE; // A free block
|
||||
zone->vm = 0;
|
||||
|
||||
#ifdef ZONEIDCHECK
|
||||
zone->id = 0;
|
||||
#endif
|
||||
|
||||
#ifdef INSTRUMENTED
|
||||
free_memory = size;
|
||||
inactive_memory = zonebase_size - size;
|
||||
active_memory = purgable_memory = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Z_Malloc
|
||||
// You can pass a NULL user if the tag is < PU_PURGELEVEL.
|
||||
// You can pass a NULL user if the tag is < PU_CACHE.
|
||||
|
||||
void *(Z_Malloc)(size_t size, int tag, void **user, const char *file, int line)
|
||||
void *Z_Malloc(size_t size, int tag, void **user)
|
||||
{
|
||||
register memblock_t *block;
|
||||
memblock_t *start;
|
||||
|
||||
#ifdef INSTRUMENTED
|
||||
size_t size_orig = size;
|
||||
#ifdef CHECKHEAP
|
||||
Z_CheckHeap();
|
||||
#endif
|
||||
|
||||
file_history[malloc_history][history_index[malloc_history]] = file;
|
||||
line_history[malloc_history][history_index[malloc_history]++] = line;
|
||||
history_index[malloc_history] &= ZONE_HISTORY-1;
|
||||
#endif
|
||||
memblock_t *block = NULL;
|
||||
|
||||
#ifdef ZONEIDCHECK
|
||||
if(tag >= PU_PURGELEVEL && !user)
|
||||
I_Error("Z_Malloc: an owner is required for purgable blocks\n"
|
||||
"Source: %s:%d", file, line);
|
||||
#endif
|
||||
if (tag == PU_CACHE && !user)
|
||||
I_Error ("Z_Malloc: An owner is required for purgable blocks");
|
||||
|
||||
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;
|
||||
if (!size)
|
||||
return user ? *user = NULL : NULL; // malloc(0) returns NULL
|
||||
|
||||
// haleyjd 06/17/08: import from EE:
|
||||
// the first if() inside the loop below contains cph's memory
|
||||
// purging efficiency fix
|
||||
while (!(block = malloc(size + HEADER_SIZE)))
|
||||
{
|
||||
if (!blockbytag[PU_CACHE])
|
||||
I_Error ("Z_Malloc: Failure trying to allocate %lu bytes", (unsigned long) size);
|
||||
Z_FreeTag(PU_CACHE);
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
// Free purgable blocks; replacement is roughly FIFO
|
||||
if(block->tag >= PU_PURGELEVEL)
|
||||
{
|
||||
start = block->prev;
|
||||
Z_Free((char *) 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 *newb =
|
||||
(memblock_t *)((char *) block + HEADER_SIZE + size);
|
||||
if (!blockbytag[tag])
|
||||
{
|
||||
blockbytag[tag] = block;
|
||||
block->next = block->prev = block;
|
||||
}
|
||||
else
|
||||
{
|
||||
blockbytag[tag]->prev->next = block;
|
||||
block->prev = blockbytag[tag]->prev;
|
||||
block->next = blockbytag[tag];
|
||||
blockbytag[tag]->prev = block;
|
||||
}
|
||||
|
||||
(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;
|
||||
newb->vm = 0;
|
||||
|
||||
#ifdef INSTRUMENTED
|
||||
inactive_memory += HEADER_SIZE;
|
||||
free_memory -= HEADER_SIZE;
|
||||
#endif
|
||||
}
|
||||
block->size = size;
|
||||
block->id = ZONEID; // signature required in block header
|
||||
block->tag = tag; // tag
|
||||
block->user = user; // user
|
||||
block = (memblock_t *)((char *) block + HEADER_SIZE);
|
||||
if (user) // if there is a user
|
||||
*user = block; // set user to point to new block
|
||||
|
||||
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
|
||||
|
||||
allocated:
|
||||
|
||||
#ifdef INSTRUMENTED
|
||||
block->file = file;
|
||||
block->line = line;
|
||||
#endif
|
||||
|
||||
#ifdef ZONEIDCHECK
|
||||
block->id = ZONEID; // signature required in block header
|
||||
#endif
|
||||
block->tag = tag; // tag
|
||||
block->user = user; // user
|
||||
block = (memblock_t *)((char *) block + HEADER_SIZE);
|
||||
if(user) // if there is a user
|
||||
*user = block; // set user to point to new block
|
||||
|
||||
#ifdef INSTRUMENTED
|
||||
Z_PrintStats(); // print memory allocation stats
|
||||
// scramble memory -- weed out any bugs
|
||||
memset(block, gametic & 0xff, size);
|
||||
#endif
|
||||
return block;
|
||||
}
|
||||
}
|
||||
while ((block = block->next) != start); // detect cycles as failure
|
||||
|
||||
// We've run out of physical memory, or so we think.
|
||||
// Although less efficient, we'll just use ordinary malloc.
|
||||
// This will squeeze the remaining juice out of this machine
|
||||
// and start cutting into virtual memory if it has it.
|
||||
|
||||
while(!(block = malloc(size + HEADER_SIZE)))
|
||||
{
|
||||
if(!blockbytag[PU_CACHE])
|
||||
I_Error("Z_Malloc: Failure trying to allocate %lu bytes"
|
||||
"\nSource: %s:%d",(unsigned long) size, file, line);
|
||||
Z_FreeTags(PU_CACHE, PU_CACHE);
|
||||
}
|
||||
|
||||
if((block->next = blockbytag[tag]))
|
||||
block->next->prev = (memblock_t *) &block->next;
|
||||
blockbytag[tag] = block;
|
||||
block->prev = (memblock_t *) &blockbytag[tag];
|
||||
block->vm = 1;
|
||||
|
||||
// haleyjd: cph's virtual memory error fix
|
||||
#ifdef INSTRUMENTED
|
||||
virtual_memory += size + HEADER_SIZE;
|
||||
|
||||
// haleyjd 06/17/08: Import from EE:
|
||||
// Big problem: extra wasn't being initialized for vm
|
||||
// blocks. This caused the memset used to randomize freed memory when
|
||||
// INSTRUMENTED is defined to stomp all over the C heap.
|
||||
block->extra = 0;
|
||||
#endif
|
||||
/* cph - the next line was lost in the #ifdef above, and also added an
|
||||
* extra HEADER_SIZE to block->size, which was incorrect */
|
||||
block->size = size;
|
||||
goto allocated;
|
||||
return block;
|
||||
}
|
||||
|
||||
void (Z_Free)(void *p, const char *file, int line)
|
||||
void Z_Free(void *p)
|
||||
{
|
||||
#ifdef INSTRUMENTED
|
||||
#ifdef CHECKHEAP
|
||||
Z_CheckHeap();
|
||||
#endif
|
||||
file_history[free_history][history_index[free_history]] = file;
|
||||
line_history[free_history][history_index[free_history]++] = line;
|
||||
history_index[free_history] &= ZONE_HISTORY-1;
|
||||
#endif
|
||||
|
||||
if(p)
|
||||
{
|
||||
memblock_t *other, *block = (memblock_t *)((char *) p - HEADER_SIZE);
|
||||
|
||||
#ifdef ZONEIDCHECK
|
||||
if(block->id != ZONEID)
|
||||
I_Error("Z_Free: freed a pointer without ZONEID\n"
|
||||
"Source: %s:%d"
|
||||
memblock_t *block = (memblock_t *)((char *) p - HEADER_SIZE);
|
||||
|
||||
#ifdef INSTRUMENTED
|
||||
"\nSource of malloc: %s:%d"
|
||||
, file, line, block->file, block->line
|
||||
#else
|
||||
, file, line
|
||||
#endif
|
||||
);
|
||||
block->id = 0; // Nullify id so another free fails
|
||||
#endif
|
||||
if (!p)
|
||||
return;
|
||||
|
||||
#ifdef INSTRUMENTED
|
||||
// scramble memory -- weed out any bugs
|
||||
memset(p, gametic & 0xff, block->size - block->extra);
|
||||
#endif
|
||||
if (block->id != ZONEID)
|
||||
I_Error("Z_Free: freed a pointer without ZONEID");
|
||||
block->id = 0; // Nullify id so another free fails
|
||||
|
||||
if(block->user) // Nullify user if one exists
|
||||
*block->user = NULL;
|
||||
|
||||
if(block->vm)
|
||||
{
|
||||
if((*(memblock_t **) block->prev = block->next))
|
||||
block->next->prev = block->prev;
|
||||
if (block->user) // Nullify user if one exists
|
||||
*block->user = NULL;
|
||||
|
||||
#ifdef INSTRUMENTED
|
||||
virtual_memory -= block->size;
|
||||
#endif
|
||||
// free(block); // [FG] TODO
|
||||
}
|
||||
else
|
||||
{
|
||||
if (block == block->next)
|
||||
blockbytag[block->tag] = NULL;
|
||||
else
|
||||
if (blockbytag[block->tag] == block)
|
||||
blockbytag[block->tag] = block->next;
|
||||
block->prev->next = block->next;
|
||||
block->next->prev = block->prev;
|
||||
|
||||
#ifdef INSTRUMENTED
|
||||
free_memory += block->size;
|
||||
inactive_memory -= block->extra;
|
||||
if(block->tag >= PU_PURGELEVEL)
|
||||
purgable_memory -= block->size - block->extra;
|
||||
else
|
||||
active_memory -= block->size - block->extra;
|
||||
#endif
|
||||
|
||||
block->tag = PU_FREE; // Mark block freed
|
||||
|
||||
if(block != zone)
|
||||
{
|
||||
other = block->prev; // Possibly merge with previous block
|
||||
if(other->tag == PU_FREE)
|
||||
{
|
||||
if(rover == block) // Move back rover if it points at block
|
||||
rover = other;
|
||||
(other->next = block->next)->prev = other;
|
||||
other->size += block->size + HEADER_SIZE;
|
||||
block = other;
|
||||
|
||||
#ifdef INSTRUMENTED
|
||||
inactive_memory -= HEADER_SIZE;
|
||||
free_memory += HEADER_SIZE;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
other = block->next; // Possibly merge with next block
|
||||
if(other->tag == PU_FREE && other != zone)
|
||||
{
|
||||
if(rover == other) // Move back rover if it points at next block
|
||||
rover = block;
|
||||
(block->next = other->next)->prev = block;
|
||||
block->size += other->size + HEADER_SIZE;
|
||||
|
||||
#ifdef INSTRUMENTED
|
||||
inactive_memory -= HEADER_SIZE;
|
||||
free_memory += HEADER_SIZE;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef INSTRUMENTED
|
||||
Z_PrintStats(); // print memory allocation stats
|
||||
#endif
|
||||
}
|
||||
free(block);
|
||||
}
|
||||
|
||||
void (Z_FreeTags)(int lowtag, int hightag, const char *file, int line)
|
||||
void Z_FreeTag(int tag)
|
||||
{
|
||||
memblock_t *block = zone;
|
||||
|
||||
if(lowtag <= PU_FREE)
|
||||
lowtag = PU_FREE+1;
|
||||
memblock_t *block, *end_block;
|
||||
|
||||
// haleyjd: code inside this do loop has been updated with
|
||||
// cph's fix for memory wastage
|
||||
|
||||
do // Scan through list, searching for tags in range
|
||||
{
|
||||
if(block->tag >= lowtag && block->tag <= hightag)
|
||||
{
|
||||
memblock_t *prev = block->prev, *cur = block;;
|
||||
(Z_Free)((char *) block + HEADER_SIZE, file, line);
|
||||
/* cph - be more careful here, we were skipping blocks!
|
||||
* If the current block was not merged with the previous,
|
||||
* cur is still a valid pointer, prev->next == cur, and cur is
|
||||
* already free so skip to the next.
|
||||
* If the current block was merged with the previous,
|
||||
* the next block to analyse is prev->next.
|
||||
* Note that the while() below does the actual step forward
|
||||
*/
|
||||
block = (prev->next == cur) ? cur : prev;
|
||||
}
|
||||
}
|
||||
while((block = block->next) != zone);
|
||||
if (tag < 0 || tag >= PU_MAX)
|
||||
I_Error("Z_FreeTag: Tag %i does not exist", tag);
|
||||
|
||||
if(hightag > PU_CACHE)
|
||||
hightag = PU_CACHE;
|
||||
|
||||
for(; lowtag <= hightag; ++lowtag)
|
||||
{
|
||||
for(block = blockbytag[lowtag], blockbytag[lowtag] = NULL; block;)
|
||||
{
|
||||
memblock_t *next = block->next;
|
||||
|
||||
#ifdef ZONEIDCHECK
|
||||
if(block->id != ZONEID)
|
||||
I_Error("Z_FreeTags: Changed a tag without ZONEID\n"
|
||||
"Source: %s:%d"
|
||||
|
||||
#ifdef INSTRUMENTED
|
||||
"\nSource of malloc: %s:%d"
|
||||
, file, line, block->file, block->line
|
||||
#else
|
||||
, file, line
|
||||
#endif
|
||||
);
|
||||
|
||||
block->id = 0; // Nullify id so another free fails
|
||||
#endif
|
||||
|
||||
#ifdef INSTRUMENTED
|
||||
virtual_memory -= block->size;
|
||||
#endif
|
||||
|
||||
if(block->user) // Nullify user if one exists
|
||||
*block->user = NULL;
|
||||
|
||||
free(block); // Free the block
|
||||
|
||||
block = next; // Advance to next block
|
||||
}
|
||||
}
|
||||
block = blockbytag[tag];
|
||||
if (!block)
|
||||
return;
|
||||
end_block = block->prev;
|
||||
while (1)
|
||||
{
|
||||
memblock_t *next = block->next;
|
||||
Z_Free((char *) block + HEADER_SIZE);
|
||||
if (block == end_block)
|
||||
break;
|
||||
block = next; // Advance to next block
|
||||
}
|
||||
}
|
||||
|
||||
void (Z_ChangeTag)(void *ptr, int tag, const char *file, int line)
|
||||
void Z_ChangeTag(void *ptr, int tag)
|
||||
{
|
||||
memblock_t *block = (memblock_t *)((char *) ptr - HEADER_SIZE);
|
||||
|
||||
#ifdef INSTRUMENTED
|
||||
#ifdef CHECKHEAP
|
||||
Z_CheckHeap();
|
||||
#endif
|
||||
#endif
|
||||
// proff - added sanity check, this can happen when an empty lump is locked
|
||||
if (!ptr)
|
||||
return;
|
||||
|
||||
// proff - do nothing if tag doesn't differ
|
||||
if (tag == block->tag)
|
||||
return;
|
||||
|
||||
#ifdef ZONEIDCHECK
|
||||
if (block->id != ZONEID)
|
||||
I_Error ("Z_ChangeTag: Changed a tag without ZONEID"
|
||||
"\nSource: %s:%d"
|
||||
I_Error ("Z_ChangeTag: freed a pointer without ZONEID");
|
||||
|
||||
#ifdef INSTRUMENTED
|
||||
"\nSource of malloc: %s:%d"
|
||||
, file, line, block->file, block->line
|
||||
#else
|
||||
, file, line
|
||||
#endif
|
||||
);
|
||||
if (tag == PU_CACHE && !block->user)
|
||||
I_Error ("Z_ChangeTag: an owner is required for purgable blocks\n");
|
||||
|
||||
if (tag >= PU_PURGELEVEL && !block->user)
|
||||
I_Error ("Z_ChangeTag: an owner is required for purgable blocks\n"
|
||||
"Source: %s:%d"
|
||||
#ifdef INSTRUMENTED
|
||||
"\nSource of malloc: %s:%d"
|
||||
, file, line, block->file, block->line
|
||||
#else
|
||||
, file, line
|
||||
#endif
|
||||
);
|
||||
|
||||
#endif // ZONEIDCHECK
|
||||
|
||||
if (block->vm)
|
||||
{
|
||||
if ((*(memblock_t **) block->prev = block->next))
|
||||
block->next->prev = block->prev;
|
||||
if ((block->next = blockbytag[tag]))
|
||||
block->next->prev = (memblock_t *) &block->next;
|
||||
block->prev = (memblock_t *) &blockbytag[tag];
|
||||
blockbytag[tag] = block;
|
||||
}
|
||||
if (block == block->next)
|
||||
blockbytag[block->tag] = NULL;
|
||||
else
|
||||
{
|
||||
#ifdef INSTRUMENTED
|
||||
if (block->tag < PU_PURGELEVEL && tag >= PU_PURGELEVEL)
|
||||
{
|
||||
active_memory -= block->size - block->extra;
|
||||
purgable_memory += block->size - block->extra;
|
||||
}
|
||||
else
|
||||
if (block->tag >= PU_PURGELEVEL && tag < PU_PURGELEVEL)
|
||||
{
|
||||
active_memory += block->size - block->extra;
|
||||
purgable_memory -= block->size - block->extra;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (blockbytag[block->tag] == block)
|
||||
blockbytag[block->tag] = block->next;
|
||||
block->prev->next = block->next;
|
||||
block->next->prev = block->prev;
|
||||
|
||||
if (!blockbytag[tag])
|
||||
{
|
||||
blockbytag[tag] = block;
|
||||
block->next = block->prev = block;
|
||||
}
|
||||
else
|
||||
{
|
||||
blockbytag[tag]->prev->next = block;
|
||||
block->prev = blockbytag[tag]->prev;
|
||||
block->next = blockbytag[tag];
|
||||
blockbytag[tag]->prev = block;
|
||||
}
|
||||
|
||||
block->tag = tag;
|
||||
}
|
||||
|
||||
void *(Z_Realloc)(void *ptr, size_t n, int tag, void **user,
|
||||
const char *file, int line)
|
||||
void *Z_Realloc(void *ptr, size_t n, int tag, void **user)
|
||||
{
|
||||
void *p = (Z_Malloc)(n, tag, user, file, line);
|
||||
if(ptr)
|
||||
{
|
||||
memblock_t *block = (memblock_t *)((char *)ptr - HEADER_SIZE);
|
||||
if(p) // haleyjd 06/17/08: allow to return NULL without crashing
|
||||
memcpy(p, ptr, n <= block->size ? n : block->size);
|
||||
(Z_Free)(ptr, file, line);
|
||||
if(user) // in case Z_Free nullified same user
|
||||
*user=p;
|
||||
}
|
||||
return p;
|
||||
void *p = Z_Malloc(n, tag, user);
|
||||
if (ptr)
|
||||
{
|
||||
memblock_t *block = (memblock_t *)((char *) ptr - HEADER_SIZE);
|
||||
memcpy(p, ptr, n <= block->size ? n : block->size);
|
||||
Z_Free(ptr);
|
||||
if (user) // in case Z_Free nullified same user
|
||||
*user=p;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
void *(Z_Calloc)(size_t n1, size_t n2, int tag, void **user,
|
||||
const char *file, int line)
|
||||
void *Z_Calloc(size_t n1, size_t n2, int tag, void **user)
|
||||
{
|
||||
return (n1*=n2) ? memset((Z_Malloc)(n1, tag, user, file, line), 0, n1) : NULL;
|
||||
}
|
||||
|
||||
char *(Z_Strdup)(const char *s, int tag, void **user,
|
||||
const char *file, int line)
|
||||
{
|
||||
return strcpy((Z_Malloc)(strlen(s)+1, tag, user, file, line), s);
|
||||
}
|
||||
|
||||
void (Z_CheckHeap)(const char *file, int line)
|
||||
{
|
||||
memblock_t *block = zone; // Start at base of zone mem
|
||||
do // Consistency check (last node treated special)
|
||||
{
|
||||
if((block->next != zone &&
|
||||
(memblock_t *)((char *) block+HEADER_SIZE+block->size) != block->next) ||
|
||||
block->next->prev != block || block->prev->next != block)
|
||||
{
|
||||
I_Error("Z_CheckHeap: Block size does not touch the next block\n"
|
||||
"Source: %s:%d"
|
||||
#ifdef INSTRUMENTED
|
||||
"\nSource of offending block: %s:%d"
|
||||
, file, line, block->file, block->line
|
||||
#else
|
||||
, file, line
|
||||
#endif
|
||||
);
|
||||
}
|
||||
}
|
||||
while((block = block->next) != zone);
|
||||
return
|
||||
(n1*=n2) ? memset(Z_Malloc(n1, tag, user), 0, n1) : NULL;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
43
src/z_zone.h
43
src/z_zone.h
@ -47,43 +47,28 @@
|
||||
// ZONE MEMORY
|
||||
// PU - purge tags.
|
||||
|
||||
enum {PU_FREE, PU_STATIC, PU_SOUND, PU_MUSIC, PU_LEVEL, PU_LEVSPEC, PU_CACHE,
|
||||
/* Must always be last -- killough */ PU_MAX};
|
||||
enum {
|
||||
PU_STATIC,
|
||||
PU_LEVEL,
|
||||
PU_CACHE,
|
||||
/* Must always be last -- killough */
|
||||
PU_MAX
|
||||
};
|
||||
|
||||
#define PU_PURGELEVEL PU_CACHE /* First purgable tag's level */
|
||||
#define PU_LEVSPEC PU_LEVEL
|
||||
|
||||
void *(Z_Malloc)(size_t size, int tag, void **ptr, const char *, int);
|
||||
void (Z_Free)(void *ptr, const char *, int);
|
||||
void (Z_FreeTags)(int lowtag, int hightag, const char *, int);
|
||||
void (Z_ChangeTag)(void *ptr, int tag, const char *, int);
|
||||
void (Z_Init)(void);
|
||||
void *(Z_Calloc)(size_t n, size_t n2, int tag, void **user, const char *, int);
|
||||
void *(Z_Realloc)(void *p, size_t n, int tag, void **user, const char *, int);
|
||||
char *(Z_Strdup)(const char *s, int tag, void **user, const char *, int);
|
||||
void (Z_CheckHeap)(const char *,int); // killough 3/22/98: add file/line info
|
||||
void Z_DumpHistory(char *);
|
||||
|
||||
#define Z_Free(a) (Z_Free) (a, __FILE__,__LINE__)
|
||||
#define Z_FreeTags(a,b) (Z_FreeTags) (a,b, __FILE__,__LINE__)
|
||||
#define Z_ChangeTag(a,b) (Z_ChangeTag)(a,b, __FILE__,__LINE__)
|
||||
#define Z_Malloc(a,b,c) (Z_Malloc) (a,b,c, __FILE__,__LINE__)
|
||||
#define Z_Strdup(a,b,c) (Z_Strdup) (a,b,c, __FILE__,__LINE__)
|
||||
#define Z_Calloc(a,b,c,d) (Z_Calloc) (a,b,c,d,__FILE__,__LINE__)
|
||||
#define Z_Realloc(a,b,c,d) (Z_Realloc) (a,b,c,d,__FILE__,__LINE__)
|
||||
#define Z_CheckHeap() (Z_CheckHeap)(__FILE__,__LINE__)
|
||||
void *Z_Malloc(size_t size, int tag, void **ptr);
|
||||
void Z_Free(void *ptr);
|
||||
void Z_FreeTag(int tag);
|
||||
void Z_ChangeTag(void *ptr, int tag);
|
||||
void *Z_Calloc(size_t n, size_t n2, int tag, void **user);
|
||||
void *Z_Realloc(void *p, size_t n, int tag, void **user);
|
||||
|
||||
// dprintf() is already declared in <stdio.h>, define it out of the way
|
||||
#define dprintf doomprintf
|
||||
// Doom-style printf
|
||||
void dprintf(const char *, ...) PRINTF_ATTR(1, 2);
|
||||
|
||||
void Z_ZoneHistory(char *);
|
||||
|
||||
#ifdef INSTRUMENTED
|
||||
extern int printstats; // killough 8/23/98
|
||||
void Z_PrintStats(void); // killough 8/23/98
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
Loading…
x
Reference in New Issue
Block a user