123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397 |
- //**************************************************************************
- //**
- //** z_zone.c : Heretic 2 : Raven Software, Corp.
- //**
- //** $RCSfile: z_zone.c,v $
- //** $Revision: 1.2 $
- //** $Date: 96/01/06 03:23:53 $
- //** $Author: bgokey $
- //**
- //**************************************************************************
- #include <stdlib.h>
- #include "h2def.h"
- /*
- ==============================================================================
- ZONE MEMORY ALLOCATION
- There is never any space between memblocks, and there will never be two
- contiguous free memblocks.
- The rover can be left pointing at a non-empty block
- It is of no value to free a cachable block, because it will get overwritten
- automatically if needed
- ==============================================================================
- */
- #define ZONEID 0x1d4a11
- typedef struct
- {
- int size; // total bytes malloced, including header
- memblock_t blocklist; // start / end cap for linked list
- memblock_t *rover;
- } memzone_t;
- memzone_t *mainzone;
- /*
- ========================
- =
- = Z_ClearZone
- =
- ========================
- */
- /*
- void Z_ClearZone (memzone_t *zone)
- {
- memblock_t *block;
-
- // set the entire zone to one free block
- zone->blocklist.next = zone->blocklist.prev = block =
- (memblock_t *)( (byte *)zone + sizeof(memzone_t) );
- zone->blocklist.user = (void *)zone;
- zone->blocklist.tag = PU_STATIC;
- zone->rover = block;
-
- block->prev = block->next = &zone->blocklist;
- block->user = NULL; // free block
- block->size = zone->size - sizeof(memzone_t);
- }
- */
- /*
- ========================
- =
- = Z_Init
- =
- ========================
- */
- void Z_Init (void)
- {
- memblock_t *block;
- int size;
- mainzone = (memzone_t *)I_ZoneBase (&size);
- mainzone->size = size;
- // set the entire zone to one free block
- mainzone->blocklist.next = mainzone->blocklist.prev = block =
- (memblock_t *)( (byte *)mainzone + sizeof(memzone_t) );
- mainzone->blocklist.user = (void *)mainzone;
- mainzone->blocklist.tag = PU_STATIC;
- mainzone->rover = block;
-
- block->prev = block->next = &mainzone->blocklist;
- block->user = NULL; // free block
- block->size = mainzone->size - sizeof(memzone_t);
- }
- /*
- ========================
- =
- = Z_Free
- =
- ========================
- */
- void Z_Free (void *ptr)
- {
- memblock_t *block, *other;
-
- block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
- if (block->id != ZONEID)
- I_Error ("Z_Free: freed a pointer without ZONEID");
-
- if (block->user > (void **)0x100) // smaller values are not pointers
- *block->user = 0; // clear the user's mark
- block->user = NULL; // mark as free
- block->tag = 0;
- block->id = 0;
-
- other = block->prev;
- if (!other->user)
- { // merge with previous free block
- other->size += block->size;
- other->next = block->next;
- other->next->prev = other;
- if (block == mainzone->rover)
- mainzone->rover = other;
- block = other;
- }
-
- other = block->next;
- if (!other->user)
- { // 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;
- }
- }
- /*
- ========================
- =
- = Z_Malloc
- =
- = You can pass a NULL user if the tag is < PU_PURGELEVEL
- ========================
- */
- #define MINFRAGMENT 64
- void *Z_Malloc (int size, int tag, void *user)
- {
- int extra;
- memblock_t *start, *rover, *new, *base;
- //
- // scan through the block list looking for the first free block
- // of sufficient size, throwing out any purgable blocks along the way
- //
- size += sizeof(memblock_t); // account for size of block header
-
-
- //
- // if there is a free block behind the rover, back up over them
- //
- base = mainzone->rover;
- if (!base->prev->user)
- base = base->prev;
-
- rover = base;
- start = base->prev;
-
- do
- {
- if (rover == start) // scaned all the way around the list
- 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)
- base = base->prev; // the rover can be the base block
- Z_Free ((byte *)rover+sizeof(memblock_t));
- base = base->next;
- rover = base->next;
- }
- }
- else
- rover = rover->next;
- } while (base->user || base->size < size);
-
- //
- // found a block big enough
- //
- extra = base->size - size;
- if (extra > MINFRAGMENT)
- { // there will be a free fragment after the allocated block
- new = (memblock_t *) ((byte *)base + size );
- new->size = extra;
- new->user = NULL; // free block
- new->tag = 0;
- new->prev = base;
- new->next = base->next;
- new->next->prev = new;
- base->next = new;
- base->size = size;
- }
-
- if (user)
- {
- base->user = user; // mark as an in use block
- *(void **)user = (void *) ((byte *)base + sizeof(memblock_t));
- }
- else
- {
- if (tag >= PU_PURGELEVEL)
- I_Error ("Z_Malloc: an owner is required for purgable blocks");
- base->user = (void *)2; // mark as in use, but unowned
- }
- base->tag = tag;
-
- mainzone->rover = base->next; // next allocation will start looking here
-
- base->id = ZONEID;
- return (void *) ((byte *)base + sizeof(memblock_t));
- }
- /*
- ========================
- =
- = Z_FreeTags
- =
- ========================
- */
- void Z_FreeTags (int lowtag, int hightag)
- {
- memblock_t *block, *next;
-
- for (block = mainzone->blocklist.next ; block != &mainzone->blocklist
- ; block = next)
- {
- next = block->next; // get link before freeing
- if (!block->user)
- continue; // free block
- if (block->tag >= lowtag && block->tag <= hightag)
- Z_Free ( (byte *)block+sizeof(memblock_t));
- }
- }
- /*
- ========================
- =
- = Z_DumpHeap
- =
- ========================
- */
- /*
- void Z_DumpHeap (int lowtag, int hightag)
- {
- memblock_t *block;
-
- printf ("zone size: %i location: %p\n",mainzone->size,mainzone);
- printf ("tag range: %i to %i\n",lowtag, hightag);
-
- for (block = mainzone->blocklist.next ; ; block = block->next)
- {
- if (block->tag >= lowtag && block->tag <= hightag)
- printf ("block:%p size:%7i user:%p tag:%3i\n",
- block, block->size, block->user, block->tag);
-
- if (block->next == &mainzone->blocklist)
- break; // all blocks have been hit
- if ( (byte *)block + block->size != (byte *)block->next)
- printf ("ERROR: block size does not touch the next block\n");
- if ( block->next->prev != block)
- printf ("ERROR: next block doesn't have proper back link\n");
- if (!block->user && !block->next->user)
- printf ("ERROR: two consecutive free blocks\n");
- }
- }
- */
- /*
- ========================
- =
- = Z_FileDumpHeap
- =
- ========================
- */
- /*
- void Z_FileDumpHeap (FILE *f)
- {
- memblock_t *block;
-
- fprintf (f,"zone size: %i location: %p\n",mainzone->size,mainzone);
-
- for (block = mainzone->blocklist.next ; ; block = block->next)
- {
- fprintf (f,"block:%p size:%7i user:%p tag:%3i\n",
- block, block->size, block->user, block->tag);
-
- if (block->next == &mainzone->blocklist)
- break; // all blocks have been hit
- if ( (byte *)block + block->size != (byte *)block->next)
- fprintf (f,"ERROR: block size does not touch the next block\n");
- if ( block->next->prev != block)
- fprintf (f,"ERROR: next block doesn't have proper back link\n");
- if (!block->user && !block->next->user)
- fprintf (f,"ERROR: two consecutive free blocks\n");
- }
- }
- */
- /*
- ========================
- =
- = Z_CheckHeap
- =
- ========================
- */
- void Z_CheckHeap (void)
- {
- memblock_t *block;
-
- for (block = mainzone->blocklist.next ; ; block = block->next)
- {
- if (block->next == &mainzone->blocklist)
- break; // all blocks have been hit
- if ( (byte *)block + block->size != (byte *)block->next)
- I_Error ("Z_CheckHeap: block size does not touch the next block\n");
- if ( block->next->prev != block)
- I_Error ("Z_CheckHeap: next block doesn't have proper back link\n");
- if (!block->user && !block->next->user)
- I_Error ("Z_CheckHeap: two consecutive free blocks\n");
- }
- }
- /*
- ========================
- =
- = Z_ChangeTag
- =
- ========================
- */
- void Z_ChangeTag2 (void *ptr, int tag)
- {
- memblock_t *block;
-
- block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t));
- if (block->id != 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");
- block->tag = tag;
- }
- /*
- ========================
- =
- = Z_FreeMemory
- =
- ========================
- */
- /*
- int Z_FreeMemory (void)
- {
- memblock_t *block;
- int free;
-
- free = 0;
- for (block = mainzone->blocklist.next ; block != &mainzone->blocklist
- ; block = block->next)
- if (!block->user || block->tag >= PU_PURGELEVEL)
- free += block->size;
- return free;
- }
- */
|