Use a new PU_FREE tag to mark free blocks, rather than the 'user' field

(avoids using magic numbers to mark allocated blocks with no user)

Subversion-branch: /trunk/chocolate-doom
Subversion-revision: 119
This commit is contained in:
Simon Howard 2005-09-22 12:58:46 +00:00
parent 53a7ee3403
commit d29e73f05a
2 changed files with 110 additions and 101 deletions

View file

@ -1,7 +1,7 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id: z_zone.c 8 2005-07-23 16:44:57Z fraggle $
// $Id: z_zone.c 119 2005-09-22 12:58:46Z fraggle $
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005 Simon Howard
@ -22,6 +22,10 @@
// 02111-1307, USA.
//
// $Log$
// Revision 1.3 2005/09/22 12:58:46 fraggle
// Use a new PU_FREE tag to mark free blocks, rather than the 'user' field
// (avoids using magic numbers to mark allocated blocks with no user)
//
// Revision 1.2 2005/07/23 16:44:57 fraggle
// Update copyright to GNU GPL
//
@ -35,7 +39,7 @@
//-----------------------------------------------------------------------------
static const char
rcsid[] = "$Id: z_zone.c 8 2005-07-23 16:44:57Z fraggle $";
rcsid[] = "$Id: z_zone.c 119 2005-09-22 12:58:46Z fraggle $";
#include "z_zone.h"
#include "i_system.h"
@ -92,8 +96,8 @@ void Z_ClearZone (memzone_t* zone)
block->prev = block->next = &zone->blocklist;
// NULL indicates a free block.
block->user = NULL;
// a free block.
block->tag = PU_FREE;
block->size = zone->size - sizeof(memzone_t);
}
@ -122,8 +126,8 @@ void Z_Init (void)
block->prev = block->next = &mainzone->blocklist;
// NULL indicates a free block.
block->user = NULL;
// free block
block->tag = PU_FREE;
block->size = mainzone->size - sizeof(memzone_t);
}
@ -142,45 +146,42 @@ void Z_Free (void* ptr)
if (block->id != ZONEID)
I_Error ("Z_Free: freed a pointer without ZONEID");
if (block->user > (void **)0x100)
if (block->tag != PU_FREE && block->user != NULL)
{
// smaller values are not pointers
// Note: OS-dependend?
// clear the user's mark
*block->user = 0;
// clear the user's mark
*block->user = 0;
}
// mark as free
block->user = NULL;
block->tag = 0;
block->tag = PU_FREE;
block->user = NULL;
block->id = 0;
other = block->prev;
if (!other->user)
if (other->tag == PU_FREE)
{
// merge with previous free block
other->size += block->size;
other->next = block->next;
other->next->prev = other;
// merge with previous free block
other->size += block->size;
other->next = block->next;
other->next->prev = other;
if (block == mainzone->rover)
mainzone->rover = other;
if (block == mainzone->rover)
mainzone->rover = other;
block = other;
block = other;
}
other = block->next;
if (!other->user)
if (other->tag == PU_FREE)
{
// merge the next free block onto the end
block->size += other->size;
block->next = other->next;
block->next->prev = block;
// merge the next free block onto the end
block->size += other->size;
block->next = other->next;
block->next->prev = block;
if (other == mainzone->rover)
mainzone->rover = block;
if (other == mainzone->rover)
mainzone->rover = block;
}
}
@ -204,6 +205,7 @@ Z_Malloc
memblock_t* rover;
memblock_t* newblock;
memblock_t* base;
void *result;
size = (size + 3) & ~3;
@ -219,42 +221,46 @@ Z_Malloc
// back up over them
base = mainzone->rover;
if (!base->prev->user)
base = base->prev;
if (base->prev->tag == PU_FREE)
base = base->prev;
rover = base;
start = base->prev;
do
{
if (rover == start)
{
// scanned all the way around the list
I_Error ("Z_Malloc: failed on allocation of %i bytes", size);
}
if (rover == start)
{
// scanned all the way around the list
Z_FileDumpHeap(stdout);
I_Error ("Z_Malloc: failed on allocation of %i bytes", size);
}
if (rover->user)
{
if (rover->tag < PU_PURGELEVEL)
{
// hit a block that can't be purged,
// so move base past it
base = rover = rover->next;
}
else
{
// free the rover block (adding the size to base)
if (rover->tag != PU_FREE)
{
if (rover->tag < PU_PURGELEVEL)
{
// hit a block that can't be purged,
// so move base past it
base = rover = rover->next;
}
else
{
// free the rover block (adding the size to base)
// the rover can be the base block
base = base->prev;
Z_Free ((byte *)rover+sizeof(memblock_t));
base = base->next;
rover = base->next;
}
}
else
rover = rover->next;
} while (base->user || base->size < size);
// the rover can be the base block
base = base->prev;
Z_Free ((byte *)rover+sizeof(memblock_t));
base = base->next;
rover = base->next;
}
}
else
{
rover = rover->next;
}
} while (base->tag != PU_FREE || base->size < size);
// found a block big enough
@ -262,43 +268,39 @@ Z_Malloc
if (extra > MINFRAGMENT)
{
// there will be a free fragment after the allocated block
newblock = (memblock_t *) ((byte *)base + size );
newblock->size = extra;
// there will be a free fragment after the allocated block
newblock = (memblock_t *) ((byte *)base + size );
newblock->size = extra;
// NULL indicates free block.
newblock->user = NULL;
newblock->tag = 0;
newblock->prev = base;
newblock->next = base->next;
newblock->next->prev = newblock;
newblock->tag = PU_FREE;
newblock->user = NULL;
newblock->prev = base;
newblock->next = base->next;
newblock->next->prev = newblock;
base->next = newblock;
base->size = size;
base->next = newblock;
base->size = size;
}
if (user)
{
// mark as an in use block
base->user = user;
*(void **)user = (void *) ((byte *)base + sizeof(memblock_t));
}
else
{
if (tag >= PU_PURGELEVEL)
if (user == NULL && tag >= PU_PURGELEVEL)
I_Error ("Z_Malloc: an owner is required for purgable blocks");
// mark as in use, but unowned
base->user = (void *)2;
}
base->user = user;
base->tag = tag;
result = (void *) ((byte *)base + sizeof(memblock_t));
if (base->user)
{
*base->user = result;
}
// next allocation will start looking here
mainzone->rover = base->next;
base->id = ZONEID;
return (void *) ((byte *)base + sizeof(memblock_t));
return result;
}
@ -322,7 +324,7 @@ Z_FreeTags
next = block->next;
// free block?
if (!block->user)
if (block->tag == PU_FREE)
continue;
if (block->tag >= lowtag && block->tag <= hightag)
@ -367,7 +369,7 @@ Z_DumpHeap
if ( block->next->prev != block)
printf ("ERROR: next block doesn't have proper back link\n");
if (!block->user && !block->next->user)
if (block->tag == PU_FREE && block->next->tag == PU_FREE)
printf ("ERROR: two consecutive free blocks\n");
}
}
@ -399,7 +401,7 @@ void Z_FileDumpHeap (FILE* f)
if ( block->next->prev != block)
fprintf (f,"ERROR: next block doesn't have proper back link\n");
if (!block->user && !block->next->user)
if (block->tag == PU_FREE && block->next->tag == PU_FREE)
fprintf (f,"ERROR: two consecutive free blocks\n");
}
}
@ -427,7 +429,7 @@ void Z_CheckHeap (void)
if ( block->next->prev != block)
I_Error ("Z_CheckHeap: next block doesn't have proper back link\n");
if (!block->user && !block->next->user)
if (block->tag == PU_FREE && block->next->tag == PU_FREE)
I_Error ("Z_CheckHeap: two consecutive free blocks\n");
}
}
@ -448,10 +450,10 @@ Z_ChangeTag2
block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
if (block->id != ZONEID)
I_Error ("Z_ChangeTag: freed a pointer without ZONEID");
I_Error ("Z_ChangeTag: freed a pointer without ZONEID");
if (tag >= PU_PURGELEVEL && (unsigned)block->user < 0x100)
I_Error ("Z_ChangeTag: an owner is required for purgable blocks");
if (tag >= PU_PURGELEVEL && block->user == NULL)
I_Error ("Z_ChangeTag: an owner is required for purgable blocks");
block->tag = tag;
}
@ -469,12 +471,13 @@ int Z_FreeMemory (void)
free = 0;
for (block = mainzone->blocklist.next ;
block != &mainzone->blocklist;
block = block->next)
block != &mainzone->blocklist;
block = block->next)
{
if (!block->user || block->tag >= PU_PURGELEVEL)
free += block->size;
if (block->tag == PU_FREE || block->tag >= PU_PURGELEVEL)
free += block->size;
}
return free;
}

View file

@ -1,7 +1,7 @@
// Emacs style mode select -*- C++ -*-
//-----------------------------------------------------------------------------
//
// $Id: z_zone.h 8 2005-07-23 16:44:57Z fraggle $
// $Id: z_zone.h 119 2005-09-22 12:58:46Z fraggle $
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005 Simon Howard
@ -40,12 +40,14 @@
// ZONE MEMORY
// PU - purge tags.
// Tags < 100 are not overwritten until freed.
#define PU_STATIC 1 // static entire execution time
#define PU_SOUND 2 // static while playing
#define PU_MUSIC 3 // static while playing
#define PU_DAVE 4 // anything else Dave wants static
#define PU_LEVEL 50 // static until level exited
#define PU_LEVSPEC 51 // a special thinker in a level
#define PU_STATIC 1 /* static entire execution time */
#define PU_SOUND 2 /* static while playing */
#define PU_MUSIC 3 /* static while playing */
#define PU_DAVE 4 /* anything else Dave wants static */
#define PU_FREE 5 /* a free block */
#define PU_LEVEL 50 /* static until level exited */
#define PU_LEVSPEC 51 /* a special thinker in a level */
// Tags >= 100 are purgable whenever needed.
#define PU_PURGELEVEL 100
#define PU_CACHE 101
@ -65,8 +67,8 @@ int Z_FreeMemory (void);
typedef struct memblock_s
{
int size; // including the header and possibly tiny fragments
void** user; // NULL if a free block
int tag; // purgelevel
void** user;
int tag; // PU_FREE if this is free
int id; // should be ZONEID
struct memblock_s* next;
struct memblock_s* prev;
@ -89,6 +91,10 @@ typedef struct memblock_s
//-----------------------------------------------------------------------------
//
// $Log$
// Revision 1.3 2005/09/22 12:58:46 fraggle
// Use a new PU_FREE tag to mark free blocks, rather than the 'user' field
// (avoids using magic numbers to mark allocated blocks with no user)
//
// Revision 1.2 2005/07/23 16:44:57 fraggle
// Update copyright to GNU GPL
//