mirror of
https://github.com/fabiangreffrath/woof.git
synced 2025-09-26 22:44:30 -04:00
Added all Eternity and PrBoom zone heap fixes (caching optimization, fragmentation optimization, savegame heap corruption, INSTRUMENTED C-heap corruption), and added th_delete thinker class to prevent infinite loops in the AI code.
This commit is contained in:
parent
26f762b64e
commit
5d5f2a10f2
@ -66,34 +66,44 @@ void P_InitThinkers(void)
|
|||||||
thinkercap.prev = thinkercap.next = &thinkercap;
|
thinkercap.prev = thinkercap.next = &thinkercap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// P_UpdateThinker
|
||||||
//
|
//
|
||||||
// killough 8/29/98:
|
// killough 8/29/98:
|
||||||
//
|
//
|
||||||
// We maintain separate threads of friends and enemies, to permit more
|
// We maintain separate threads of friends and enemies, to permit more
|
||||||
// efficient searches.
|
// efficient searches.
|
||||||
//
|
//
|
||||||
|
// haleyjd 6/17/08: Import from EE: PrBoom bugfixes, including addition of the
|
||||||
|
// th_delete thinker class to rectify problems with infinite loops in the AI
|
||||||
|
// code due to corruption of the th_enemies/th_friends lists when monsters get
|
||||||
|
// removed at an inopportune moment.
|
||||||
|
//
|
||||||
void P_UpdateThinker(thinker_t *thinker)
|
void P_UpdateThinker(thinker_t *thinker)
|
||||||
{
|
{
|
||||||
// find the class the thinker belongs to
|
register thinker_t *th;
|
||||||
|
|
||||||
int class = thinker->function == P_MobjThinker &&
|
|
||||||
((mobj_t *) thinker)->health > 0 &&
|
|
||||||
(((mobj_t *) thinker)->flags & MF_COUNTKILL ||
|
|
||||||
((mobj_t *) thinker)->type == MT_SKULL) ?
|
|
||||||
((mobj_t *) thinker)->flags & MF_FRIEND ?
|
|
||||||
th_friends : th_enemies : th_misc;
|
|
||||||
|
|
||||||
// Remove from current thread
|
// find the class the thinker belongs to
|
||||||
thinker_t *th = thinker->cnext;
|
|
||||||
(th->cprev = thinker->cprev)->cnext = th;
|
|
||||||
|
|
||||||
// Add to appropriate thread
|
// haleyjd 07/12/03: don't use "class" as a variable name
|
||||||
th = &thinkerclasscap[class];
|
int tclass = thinker->function == P_RemoveThinkerDelayed ? th_delete :
|
||||||
th->cprev->cnext = thinker;
|
thinker->function == P_MobjThinker &&
|
||||||
thinker->cnext = th;
|
((mobj_t *) thinker)->health > 0 &&
|
||||||
thinker->cprev = th->cprev;
|
(((mobj_t *) thinker)->flags & MF_COUNTKILL ||
|
||||||
th->cprev = thinker;
|
((mobj_t *) thinker)->type == MT_SKULL) ?
|
||||||
|
((mobj_t *) thinker)->flags & MF_FRIEND ?
|
||||||
|
th_friends : th_enemies : th_misc;
|
||||||
|
|
||||||
|
// Remove from current thread, if in one -- haleyjd: from PrBoom
|
||||||
|
if((th = thinker->cnext) != NULL)
|
||||||
|
(th->cprev = thinker->cprev)->cnext = th;
|
||||||
|
|
||||||
|
// Add to appropriate thread
|
||||||
|
th = &thinkerclasscap[tclass];
|
||||||
|
th->cprev->cnext = thinker;
|
||||||
|
thinker->cnext = th;
|
||||||
|
thinker->cprev = th->cprev;
|
||||||
|
th->cprev = thinker;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -133,15 +143,18 @@ static thinker_t *currentthinker;
|
|||||||
// remove it, and set currentthinker to one node preceeding it, so
|
// remove it, and set currentthinker to one node preceeding it, so
|
||||||
// that the next step in P_RunThinkers() will get its successor.
|
// that the next step in P_RunThinkers() will get its successor.
|
||||||
//
|
//
|
||||||
|
|
||||||
void P_RemoveThinkerDelayed(thinker_t *thinker)
|
void P_RemoveThinkerDelayed(thinker_t *thinker)
|
||||||
{
|
{
|
||||||
if (!thinker->references)
|
if(!thinker->references)
|
||||||
{
|
{
|
||||||
thinker_t *next = thinker->next;
|
thinker_t *next = thinker->next;
|
||||||
(next->prev = currentthinker = thinker->prev)->next = next;
|
(next->prev = currentthinker = thinker->prev)->next = next;
|
||||||
|
|
||||||
|
// haleyjd 6/17/08: remove from threaded list now
|
||||||
|
(thinker->cnext->cprev = thinker->cprev)->cnext = thinker->cnext;
|
||||||
|
|
||||||
Z_Free(thinker);
|
Z_Free(thinker);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -156,13 +169,24 @@ void P_RemoveThinkerDelayed(thinker_t *thinker)
|
|||||||
// set the function to P_RemoveThinkerDelayed(), so that later, it will be
|
// set the function to P_RemoveThinkerDelayed(), so that later, it will be
|
||||||
// removed automatically as part of the thinker process.
|
// removed automatically as part of the thinker process.
|
||||||
//
|
//
|
||||||
|
|
||||||
void P_RemoveThinker(thinker_t *thinker)
|
void P_RemoveThinker(thinker_t *thinker)
|
||||||
{
|
{
|
||||||
thinker->function = P_RemoveThinkerDelayed;
|
thinker->function = P_RemoveThinkerDelayed;
|
||||||
|
|
||||||
|
// killough 8/29/98: remove immediately from threaded list
|
||||||
|
|
||||||
// killough 8/29/98: remove immediately from threaded list
|
// haleyjd 06/17/08: Import from EE:
|
||||||
(thinker->cnext->cprev = thinker->cprev)->cnext = thinker->cnext;
|
// NO! Doing this here was always suspect to me, and
|
||||||
|
// sure enough: if a monster's removed at the wrong time, it gets put
|
||||||
|
// back into the list improperly and starts causing an infinite loop in
|
||||||
|
// the AI code. We'll follow PrBoom's lead and create a th_delete class
|
||||||
|
// for thinkers awaiting deferred removal.
|
||||||
|
|
||||||
|
// Old code:
|
||||||
|
//(thinker->cnext->cprev = thinker->cprev)->cnext = thinker->cnext;
|
||||||
|
|
||||||
|
// Move to th_delete class.
|
||||||
|
P_UpdateThinker(thinker);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -46,10 +46,11 @@ void P_SetTarget(mobj_t **mo, mobj_t *target); // killough 11/98
|
|||||||
|
|
||||||
// killough 8/29/98: threads of thinkers, for more efficient searches
|
// killough 8/29/98: threads of thinkers, for more efficient searches
|
||||||
typedef enum {
|
typedef enum {
|
||||||
th_misc,
|
th_delete, // haleyjd 11/09/06: giant bug fix
|
||||||
th_friends,
|
th_misc,
|
||||||
th_enemies,
|
th_friends,
|
||||||
NUMTHCLASS
|
th_enemies,
|
||||||
|
NUMTHCLASS
|
||||||
} th_class;
|
} th_class;
|
||||||
|
|
||||||
extern thinker_t thinkerclasscap[];
|
extern thinker_t thinkerclasscap[];
|
||||||
|
451
Source/Z_zone.c
451
Source/Z_zone.c
@ -38,6 +38,7 @@ static const char rcsid[] = "$Id: z_zone.c,v 1.13 1998/05/12 06:11:55 killough E
|
|||||||
|
|
||||||
#include "z_zone.h"
|
#include "z_zone.h"
|
||||||
#include "doomstat.h"
|
#include "doomstat.h"
|
||||||
|
#include "m_argv.h"
|
||||||
|
|
||||||
#ifdef DJGPP
|
#ifdef DJGPP
|
||||||
#include <dpmi.h>
|
#include <dpmi.h>
|
||||||
@ -267,156 +268,177 @@ void Z_Init(void)
|
|||||||
|
|
||||||
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, const char *file, int line)
|
||||||
{
|
{
|
||||||
register memblock_t *block;
|
register memblock_t *block;
|
||||||
memblock_t *start;
|
memblock_t *start;
|
||||||
|
|
||||||
#ifdef INSTRUMENTED
|
#ifdef INSTRUMENTED
|
||||||
size_t size_orig = size;
|
size_t size_orig = size;
|
||||||
#ifdef CHECKHEAP
|
#ifdef CHECKHEAP
|
||||||
Z_CheckHeap();
|
Z_CheckHeap();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
file_history[malloc_history][history_index[malloc_history]] = file;
|
file_history[malloc_history][history_index[malloc_history]] = file;
|
||||||
line_history[malloc_history][history_index[malloc_history]++] = line;
|
line_history[malloc_history][history_index[malloc_history]++] = line;
|
||||||
history_index[malloc_history] &= ZONE_HISTORY-1;
|
history_index[malloc_history] &= ZONE_HISTORY-1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ZONEIDCHECK
|
#ifdef ZONEIDCHECK
|
||||||
if (tag >= PU_PURGELEVEL && !user)
|
if(tag >= PU_PURGELEVEL && !user)
|
||||||
I_Error ("Z_Malloc: an owner is required for purgable blocks\n"
|
I_Error("Z_Malloc: an owner is required for purgable blocks\n"
|
||||||
"Source: %s:%d", file, line);
|
"Source: %s:%d", file, line);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!size)
|
if(!size)
|
||||||
return user ? *user = NULL : NULL; // malloc(0) returns NULL
|
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;
|
||||||
|
|
||||||
size = (size+CHUNK_SIZE-1) & ~(CHUNK_SIZE-1); // round to chunk size
|
// haleyjd 06/17/08: import from EE:
|
||||||
|
// the first if() inside the loop below contains cph's memory
|
||||||
|
// purging efficiency fix
|
||||||
|
|
||||||
block = rover;
|
do
|
||||||
|
{
|
||||||
if (block->prev->tag == PU_FREE)
|
// Free purgable blocks; replacement is roughly FIFO
|
||||||
block = block->prev;
|
if(block->tag >= PU_PURGELEVEL)
|
||||||
|
{
|
||||||
start = block;
|
start = block->prev;
|
||||||
|
Z_Free((char *) block + HEADER_SIZE);
|
||||||
do
|
/* cph - If start->next == block, we did not merge with the previous
|
||||||
{
|
* If !=, we did, so we continue from start.
|
||||||
if (block->tag >= PU_PURGELEVEL) // Free purgable blocks
|
* Important: we've reset start!
|
||||||
{ // replacement is roughly FIFO
|
*/
|
||||||
start = block->prev;
|
if(start->next == block)
|
||||||
Z_Free((char *) block + HEADER_SIZE);
|
start = start->next;
|
||||||
block = start = start->next; // Important: resets start
|
else
|
||||||
}
|
block = start;
|
||||||
|
}
|
||||||
if (block->tag == PU_FREE && block->size >= size) // First-fit
|
|
||||||
{
|
if(block->tag == PU_FREE && block->size >= size) // First-fit
|
||||||
size_t extra = block->size - size;
|
{
|
||||||
if (extra >= MIN_BLOCK_SPLIT + HEADER_SIZE)
|
size_t extra = block->size - size;
|
||||||
{
|
if(extra >= MIN_BLOCK_SPLIT + HEADER_SIZE)
|
||||||
memblock_t *newb = (memblock_t *)((char *) block +
|
{
|
||||||
HEADER_SIZE + size);
|
memblock_t *newb =
|
||||||
|
(memblock_t *)((char *) 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;
|
|
||||||
newb->vm = 0;
|
|
||||||
|
|
||||||
|
(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
|
#ifdef INSTRUMENTED
|
||||||
inactive_memory += HEADER_SIZE;
|
inactive_memory += HEADER_SIZE;
|
||||||
free_memory -= HEADER_SIZE;
|
free_memory -= HEADER_SIZE;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
rover = block->next; // set roving pointer for next search
|
|
||||||
|
|
||||||
|
rover = block->next; // set roving pointer for next search
|
||||||
|
|
||||||
#ifdef INSTRUMENTED
|
#ifdef INSTRUMENTED
|
||||||
inactive_memory += block->extra = block->size - size_orig;
|
inactive_memory += block->extra = block->size - size_orig;
|
||||||
if (tag >= PU_PURGELEVEL)
|
if(tag >= PU_PURGELEVEL)
|
||||||
purgable_memory += size_orig;
|
purgable_memory += size_orig;
|
||||||
else
|
else
|
||||||
active_memory += size_orig;
|
active_memory += size_orig;
|
||||||
free_memory -= block->size;
|
free_memory -= block->size;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
allocated:
|
allocated:
|
||||||
|
|
||||||
#ifdef INSTRUMENTED
|
#ifdef INSTRUMENTED
|
||||||
block->file = file;
|
block->file = file;
|
||||||
block->line = line;
|
block->line = line;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ZONEIDCHECK
|
#ifdef ZONEIDCHECK
|
||||||
block->id = ZONEID; // signature required in block header
|
block->id = ZONEID; // signature required in block header
|
||||||
#endif
|
#endif
|
||||||
block->tag = tag; // tag
|
block->tag = tag; // tag
|
||||||
block->user = user; // user
|
block->user = user; // user
|
||||||
block = (memblock_t *)((char *) block + HEADER_SIZE);
|
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
|
*user = block; // set user to point to new block
|
||||||
|
|
||||||
#ifdef INSTRUMENTED
|
#ifdef INSTRUMENTED
|
||||||
Z_PrintStats(); // print memory allocation stats
|
Z_PrintStats(); // print memory allocation stats
|
||||||
// scramble memory -- weed out any bugs
|
// scramble memory -- weed out any bugs
|
||||||
memset(block, gametic & 0xff, size);
|
memset(block, gametic & 0xff, size);
|
||||||
#endif
|
#endif
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while ((block = block->next) != start); // detect cycles as failure
|
while ((block = block->next) != start); // detect cycles as failure
|
||||||
|
|
||||||
// We've run out of physical memory, or so we think.
|
// We've run out of physical memory, or so we think.
|
||||||
// Although less efficient, we'll just use ordinary malloc.
|
// Although less efficient, we'll just use ordinary malloc.
|
||||||
// This will squeeze the remaining juice out of this machine
|
// This will squeeze the remaining juice out of this machine
|
||||||
// and start cutting into virtual memory if it has it.
|
// and start cutting into virtual memory if it has it.
|
||||||
|
|
||||||
while (!(block = (malloc)(size + HEADER_SIZE)))
|
while(!(block = (malloc)(size + HEADER_SIZE)))
|
||||||
{
|
{
|
||||||
if (!blockbytag[PU_CACHE])
|
if(!blockbytag[PU_CACHE])
|
||||||
I_Error ("Z_Malloc: Failure trying to allocate %lu bytes"
|
I_Error("Z_Malloc: Failure trying to allocate %lu bytes"
|
||||||
"\nSource: %s:%d",(unsigned long) size, file, line);
|
"\nSource: %s:%d",(unsigned long) size, file, line);
|
||||||
Z_FreeTags(PU_CACHE,PU_CACHE);
|
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;
|
|
||||||
|
|
||||||
|
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
|
#ifdef INSTRUMENTED
|
||||||
virtual_memory += block->size = size + HEADER_SIZE;
|
virtual_memory += size + HEADER_SIZE;
|
||||||
#endif
|
|
||||||
|
|
||||||
goto allocated;
|
// 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, const char *file, int line)
|
||||||
{
|
{
|
||||||
#ifdef INSTRUMENTED
|
#ifdef INSTRUMENTED
|
||||||
#ifdef CHECKHEAP
|
#ifdef CHECKHEAP
|
||||||
Z_CheckHeap();
|
Z_CheckHeap();
|
||||||
#endif
|
#endif
|
||||||
file_history[free_history][history_index[free_history]] = file;
|
file_history[free_history][history_index[free_history]] = file;
|
||||||
line_history[free_history][history_index[free_history]++] = line;
|
line_history[free_history][history_index[free_history]++] = line;
|
||||||
history_index[free_history] &= ZONE_HISTORY-1;
|
history_index[free_history] &= ZONE_HISTORY-1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (p)
|
if(p)
|
||||||
{
|
{
|
||||||
memblock_t *other, *block = (memblock_t *)((char *) p - HEADER_SIZE);
|
memblock_t *other, *block = (memblock_t *)((char *) p - HEADER_SIZE);
|
||||||
|
|
||||||
#ifdef ZONEIDCHECK
|
#ifdef ZONEIDCHECK
|
||||||
if (block->id != ZONEID)
|
if(block->id != ZONEID)
|
||||||
I_Error("Z_Free: freed a pointer without ZONEID\n"
|
I_Error("Z_Free: freed a pointer without ZONEID\n"
|
||||||
"Source: %s:%d"
|
"Source: %s:%d"
|
||||||
|
|
||||||
#ifdef INSTRUMENTED
|
#ifdef INSTRUMENTED
|
||||||
"\nSource of malloc: %s:%d"
|
"\nSource of malloc: %s:%d"
|
||||||
, file, line, block->file, block->line
|
, file, line, block->file, block->line
|
||||||
#else
|
#else
|
||||||
, file, line
|
, file, line
|
||||||
#endif
|
#endif
|
||||||
);
|
);
|
||||||
block->id = 0; // Nullify id so another free fails
|
block->id = 0; // Nullify id so another free fails
|
||||||
@ -427,123 +449,138 @@ void (Z_Free)(void *p, const char *file, int line)
|
|||||||
memset(p, gametic & 0xff, block->size - block->extra);
|
memset(p, gametic & 0xff, block->size - block->extra);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (block->user) // Nullify user if one exists
|
if(block->user) // Nullify user if one exists
|
||||||
*block->user = NULL;
|
*block->user = NULL;
|
||||||
|
|
||||||
if (block->vm)
|
if(block->vm)
|
||||||
{
|
{
|
||||||
if ((*(memblock_t **) block->prev = block->next))
|
if((*(memblock_t **) block->prev = block->next))
|
||||||
block->next->prev = block->prev;
|
block->next->prev = block->prev;
|
||||||
|
|
||||||
#ifdef INSTRUMENTED
|
#ifdef INSTRUMENTED
|
||||||
virtual_memory -= block->size;
|
virtual_memory -= block->size;
|
||||||
#endif
|
#endif
|
||||||
(free)(block);
|
(free)(block);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
#ifdef INSTRUMENTED
|
#ifdef INSTRUMENTED
|
||||||
free_memory += block->size;
|
free_memory += block->size;
|
||||||
inactive_memory -= block->extra;
|
inactive_memory -= block->extra;
|
||||||
if (block->tag >= PU_PURGELEVEL)
|
if(block->tag >= PU_PURGELEVEL)
|
||||||
purgable_memory -= block->size - block->extra;
|
purgable_memory -= block->size - block->extra;
|
||||||
else
|
else
|
||||||
active_memory -= block->size - block->extra;
|
active_memory -= block->size - block->extra;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
block->tag = PU_FREE; // Mark block freed
|
block->tag = PU_FREE; // Mark block freed
|
||||||
|
|
||||||
if (block != zone)
|
if(block != zone)
|
||||||
|
{
|
||||||
|
other = block->prev; // Possibly merge with previous block
|
||||||
|
if(other->tag == PU_FREE)
|
||||||
{
|
{
|
||||||
other = block->prev; // Possibly merge with previous block
|
if(rover == block) // Move back rover if it points at block
|
||||||
if (other->tag == PU_FREE)
|
rover = other;
|
||||||
{
|
(other->next = block->next)->prev = other;
|
||||||
if (rover == block) // Move back rover if it points at block
|
other->size += block->size + HEADER_SIZE;
|
||||||
rover = other;
|
block = other;
|
||||||
(other->next = block->next)->prev = other;
|
|
||||||
other->size += block->size + HEADER_SIZE;
|
|
||||||
block = other;
|
|
||||||
|
|
||||||
#ifdef INSTRUMENTED
|
#ifdef INSTRUMENTED
|
||||||
inactive_memory -= HEADER_SIZE;
|
inactive_memory -= HEADER_SIZE;
|
||||||
free_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
|
#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
|
#ifdef INSTRUMENTED
|
||||||
Z_PrintStats(); // print memory allocation stats
|
Z_PrintStats(); // print memory allocation stats
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void (Z_FreeTags)(int lowtag, int hightag, const char *file, int line)
|
void (Z_FreeTags)(int lowtag, int hightag, const char *file, int line)
|
||||||
{
|
{
|
||||||
memblock_t *block = zone;
|
memblock_t *block = zone;
|
||||||
|
|
||||||
|
if(lowtag <= PU_FREE)
|
||||||
|
lowtag = PU_FREE+1;
|
||||||
|
|
||||||
if (lowtag <= PU_FREE)
|
// haleyjd: code inside this do loop has been updated with
|
||||||
lowtag = PU_FREE+1;
|
// cph's fix for memory wastage
|
||||||
|
|
||||||
do // Scan through list, searching for tags in range
|
do // Scan through list, searching for tags in range
|
||||||
if (block->tag >= lowtag && block->tag <= hightag)
|
{
|
||||||
|
if(block->tag >= lowtag && block->tag <= hightag)
|
||||||
{
|
{
|
||||||
memblock_t *prev = block->prev;
|
memblock_t *prev = block->prev, *cur = block;;
|
||||||
(Z_Free)((char *) block + HEADER_SIZE, file, line);
|
(Z_Free)((char *) block + HEADER_SIZE, file, line);
|
||||||
block = prev->next;
|
/* 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);
|
}
|
||||||
|
while((block = block->next) != zone);
|
||||||
|
|
||||||
if (hightag > PU_CACHE)
|
if(hightag > PU_CACHE)
|
||||||
hightag = PU_CACHE;
|
hightag = PU_CACHE;
|
||||||
|
|
||||||
for (;lowtag <= hightag; lowtag++)
|
for(; lowtag <= hightag; ++lowtag)
|
||||||
for (block = blockbytag[lowtag], blockbytag[lowtag] = NULL; block;)
|
{
|
||||||
|
for(block = blockbytag[lowtag], blockbytag[lowtag] = NULL; block;)
|
||||||
{
|
{
|
||||||
memblock_t *next = block->next;
|
memblock_t *next = block->next;
|
||||||
|
|
||||||
#ifdef ZONEIDCHECK
|
#ifdef ZONEIDCHECK
|
||||||
if (block->id != ZONEID)
|
if(block->id != ZONEID)
|
||||||
I_Error("Z_FreeTags: Changed a tag without ZONEID\n"
|
I_Error("Z_FreeTags: Changed a tag without ZONEID\n"
|
||||||
"Source: %s:%d"
|
"Source: %s:%d"
|
||||||
|
|
||||||
#ifdef INSTRUMENTED
|
#ifdef INSTRUMENTED
|
||||||
"\nSource of malloc: %s:%d"
|
"\nSource of malloc: %s:%d"
|
||||||
, file, line, block->file, block->line
|
, file, line, block->file, block->line
|
||||||
#else
|
#else
|
||||||
, file, line
|
, file, line
|
||||||
#endif
|
#endif
|
||||||
);
|
);
|
||||||
|
|
||||||
block->id = 0; // Nullify id so another free fails
|
block->id = 0; // Nullify id so another free fails
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef INSTRUMENTED
|
#ifdef INSTRUMENTED
|
||||||
virtual_memory -= block->size;
|
virtual_memory -= block->size;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (block->user) // Nullify user if one exists
|
if(block->user) // Nullify user if one exists
|
||||||
*block->user = NULL;
|
*block->user = NULL;
|
||||||
|
|
||||||
(free)(block); // Free the block
|
(free)(block); // Free the block
|
||||||
|
|
||||||
block = next; // Advance to next block
|
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, const char *file, int line)
|
||||||
@ -613,48 +650,52 @@ void (Z_ChangeTag)(void *ptr, int tag, const char *file, int line)
|
|||||||
void *(Z_Realloc)(void *ptr, size_t n, int tag, void **user,
|
void *(Z_Realloc)(void *ptr, size_t n, int tag, void **user,
|
||||||
const char *file, int line)
|
const char *file, int line)
|
||||||
{
|
{
|
||||||
void *p = (Z_Malloc)(n, tag, user, file, line);
|
void *p = (Z_Malloc)(n, tag, user, file, line);
|
||||||
if (ptr)
|
if(ptr)
|
||||||
{
|
{
|
||||||
memblock_t *block = (memblock_t *)((char *) ptr - HEADER_SIZE);
|
memblock_t *block = (memblock_t *)((char *)ptr - HEADER_SIZE);
|
||||||
memcpy(p, ptr, n <= block->size ? n : block->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);
|
(Z_Free)(ptr, file, line);
|
||||||
if (user) // in case Z_Free nullified same user
|
if(user) // in case Z_Free nullified same user
|
||||||
*user=p;
|
*user=p;
|
||||||
}
|
}
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *(Z_Calloc)(size_t n1, size_t n2, int tag, void **user,
|
void *(Z_Calloc)(size_t n1, size_t n2, int tag, void **user,
|
||||||
const char *file, int line)
|
const char *file, int line)
|
||||||
{
|
{
|
||||||
return
|
return (n1*=n2) ? memset((Z_Malloc)(n1, tag, user, file, line), 0, n1) : NULL;
|
||||||
(n1*=n2) ? memset((Z_Malloc)(n1, tag, user, file, line), 0, n1) : NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char *(Z_Strdup)(const char *s, int tag, void **user,
|
char *(Z_Strdup)(const char *s, int tag, void **user,
|
||||||
const char *file, int line)
|
const char *file, int line)
|
||||||
{
|
{
|
||||||
return strcpy((Z_Malloc)(strlen(s)+1, tag, user, file, line), s);
|
return strcpy((Z_Malloc)(strlen(s)+1, tag, user, file, line), s);
|
||||||
}
|
}
|
||||||
|
|
||||||
void (Z_CheckHeap)(const char *file, int line)
|
void (Z_CheckHeap)(const char *file, int line)
|
||||||
{
|
{
|
||||||
memblock_t *block = zone; // Start at base of zone mem
|
memblock_t *block = zone; // Start at base of zone mem
|
||||||
do // Consistency check (last node treated special)
|
do // Consistency check (last node treated special)
|
||||||
if ((block->next != zone &&
|
{
|
||||||
(memblock_t *)((char *) block+HEADER_SIZE+block->size) != block->next)
|
if((block->next != zone &&
|
||||||
|| block->next->prev != block || block->prev->next != block)
|
(memblock_t *)((char *) block+HEADER_SIZE+block->size) != block->next) ||
|
||||||
I_Error("Z_CheckHeap: Block size does not touch the next block\n"
|
block->next->prev != block || block->prev->next != block)
|
||||||
"Source: %s:%d"
|
{
|
||||||
|
I_Error("Z_CheckHeap: Block size does not touch the next block\n"
|
||||||
|
"Source: %s:%d"
|
||||||
#ifdef INSTRUMENTED
|
#ifdef INSTRUMENTED
|
||||||
"\nSource of offending block: %s:%d"
|
"\nSource of offending block: %s:%d"
|
||||||
, file, line, block->file, block->line
|
, file, line, block->file, block->line
|
||||||
#else
|
#else
|
||||||
, file, line
|
, file, line
|
||||||
#endif
|
#endif
|
||||||
);
|
);
|
||||||
while ((block=block->next) != zone);
|
}
|
||||||
|
}
|
||||||
|
while((block = block->next) != zone);
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
Loading…
x
Reference in New Issue
Block a user