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:
Fabian Greffrath 2022-06-24 09:01:49 +02:00 committed by GitHub
parent 5cbd8e49d1
commit 0e6e346b32
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 131 additions and 681 deletions

View File

@ -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)

View File

@ -178,8 +178,6 @@ static void MissionSet(void)
void D_DoomMain(void)
{
Z_Init();
//SetupMission(MissionSet);
MissionSet();

View File

@ -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()

View File

@ -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);

View File

@ -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

View File

@ -1670,8 +1670,6 @@ void I_ResetScreen(void)
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();
}

View File

@ -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()
{

View File

@ -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);

View File

@ -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();

View File

@ -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;
memblock_t *block = NULL;
#ifdef INSTRUMENTED
size_t size_orig = size;
#ifdef CHECKHEAP
Z_CheckHeap();
#endif
if (tag == PU_CACHE && !user)
I_Error ("Z_Malloc: An owner is required for purgable blocks");
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
#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(!size)
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 06/17/08: import from EE:
// the first if() inside the loop below contains cph's memory
// purging efficiency fix
do
while (!(block = malloc(size + HEADER_SIZE)))
{
// 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 (!blockbytag[PU_CACHE])
I_Error ("Z_Malloc: Failure trying to allocate %lu bytes", (unsigned long) size);
Z_FreeTag(PU_CACHE);
}
if(block->tag == PU_FREE && block->size >= size) // First-fit
if (!blockbytag[tag])
{
size_t extra = block->size - size;
if(extra >= MIN_BLOCK_SPLIT + HEADER_SIZE)
blockbytag[tag] = block;
block->next = block->prev = block;
}
else
{
memblock_t *newb =
(memblock_t *)((char *) block + HEADER_SIZE + size);
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
}
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
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;
}
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
memblock_t *block = (memblock_t *)((char *) p - HEADER_SIZE);
if(p)
{
memblock_t *other, *block = (memblock_t *)((char *) p - HEADER_SIZE);
if (!p)
return;
#ifdef ZONEIDCHECK
if(block->id != ZONEID)
I_Error("Z_Free: freed a pointer without ZONEID\n"
"Source: %s:%d"
#ifdef INSTRUMENTED
"\nSource of malloc: %s:%d"
, file, line, block->file, block->line
#else
, file, line
#endif
);
if (block->id != ZONEID)
I_Error("Z_Free: freed a pointer without ZONEID");
block->id = 0; // Nullify id so another free fails
#endif
#ifdef INSTRUMENTED
// scramble memory -- weed out any bugs
memset(p, gametic & 0xff, block->size - block->extra);
#endif
if(block->user) // Nullify user if one exists
if (block->user) // Nullify user if one exists
*block->user = NULL;
if(block->vm)
{
if((*(memblock_t **) block->prev = block->next))
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
virtual_memory -= block->size;
#endif
// free(block); // [FG] TODO
}
else
{
#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;
memblock_t *block, *end_block;
if(lowtag <= PU_FREE)
lowtag = PU_FREE+1;
if (tag < 0 || tag >= PU_MAX)
I_Error("Z_FreeTag: Tag %i does not exist", tag);
// 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(hightag > PU_CACHE)
hightag = PU_CACHE;
for(; lowtag <= hightag; ++lowtag)
{
for(block = blockbytag[lowtag], blockbytag[lowtag] = NULL; block;)
block = blockbytag[tag];
if (!block)
return;
end_block = block->prev;
while (1)
{
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
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))
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;
if ((block->next = blockbytag[tag]))
block->next->prev = (memblock_t *) &block->next;
block->prev = (memblock_t *) &blockbytag[tag];
if (!blockbytag[tag])
{
blockbytag[tag] = block;
block->next = block->prev = block;
}
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
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)
void *p = Z_Malloc(n, tag, user);
if (ptr)
{
memblock_t *block = (memblock_t *)((char *)ptr - HEADER_SIZE);
if(p) // haleyjd 06/17/08: allow to return NULL without crashing
memblock_t *block = (memblock_t *)((char *) ptr - HEADER_SIZE);
memcpy(p, ptr, n <= block->size ? n : block->size);
(Z_Free)(ptr, file, line);
if(user) // in case Z_Free nullified same user
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;
}
//-----------------------------------------------------------------------------

View File

@ -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
//----------------------------------------------------------------------------