From a8f828a066773a59fdf646299359d35ae0e845af Mon Sep 17 00:00:00 2001 From: wyatt8740 Date: Mon, 6 Jan 2014 12:02:16 -0500 Subject: Removed accidental upload of copyrighted map files --- WinQuake/zone.c | 1870 +++++++++++++++++++++++++++---------------------------- 1 file changed, 935 insertions(+), 935 deletions(-) (limited to 'WinQuake/zone.c') diff --git a/WinQuake/zone.c b/WinQuake/zone.c index e30d7f8..42d7c45 100644 --- a/WinQuake/zone.c +++ b/WinQuake/zone.c @@ -1,935 +1,935 @@ -/* -Copyright (C) 1996-1997 Id Software, Inc. - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -*/ -// Z_zone.c - -#include "quakedef.h" - -#define DYNAMIC_SIZE 0xc000 - -#define ZONEID 0x1d4a11 -#define MINFRAGMENT 64 - -typedef struct memblock_s -{ - int size; // including the header and possibly tiny fragments - int tag; // a tag of 0 is a free block - int id; // should be ZONEID - struct memblock_s *next, *prev; - int pad; // pad to 64 bit boundary -} memblock_t; - -typedef struct -{ - int size; // total bytes malloced, including header - memblock_t blocklist; // start / end cap for linked list - memblock_t *rover; -} memzone_t; - -void Cache_FreeLow (int new_low_hunk); -void Cache_FreeHigh (int new_high_hunk); - - -/* -============================================================================== - - 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 - -The zone calls are pretty much only used for small strings and structures, -all big things are allocated on the hunk. -============================================================================== -*/ - -memzone_t *mainzone; - -void Z_ClearZone (memzone_t *zone, int size); - - -/* -======================== -Z_ClearZone -======================== -*/ -void Z_ClearZone (memzone_t *zone, int size) -{ - 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.tag = 1; // in use block - zone->blocklist.id = 0; - zone->blocklist.size = 0; - zone->rover = block; - - block->prev = block->next = &zone->blocklist; - block->tag = 0; // free block - block->id = ZONEID; - block->size = size - sizeof(memzone_t); -} - - -/* -======================== -Z_Free -======================== -*/ -void Z_Free (void *ptr) -{ - memblock_t *block, *other; - - if (!ptr) - Sys_Error ("Z_Free: NULL pointer"); - - block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t)); - if (block->id != ZONEID) - Sys_Error ("Z_Free: freed a pointer without ZONEID"); - if (block->tag == 0) - Sys_Error ("Z_Free: freed a freed pointer"); - - block->tag = 0; // mark as free - - other = block->prev; - if (!other->tag) - { // 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->tag) - { // 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 -======================== -*/ -void *Z_Malloc (int size) -{ - void *buf; - -Z_CheckHeap (); // DEBUG - buf = Z_TagMalloc (size, 1); - if (!buf) - Sys_Error ("Z_Malloc: failed on allocation of %i bytes",size); - Q_memset (buf, 0, size); - - return buf; -} - -void *Z_TagMalloc (int size, int tag) -{ - int extra; - memblock_t *start, *rover, *new, *base; - - if (!tag) - Sys_Error ("Z_TagMalloc: tried to use a 0 tag"); - -// -// scan through the block list looking for the first free block -// of sufficient size -// - size += sizeof(memblock_t); // account for size of block header - size += 4; // space for memory trash tester - size = (size + 7) & ~7; // align to 8-byte boundary - - base = rover = mainzone->rover; - start = base->prev; - - do - { - if (rover == start) // scaned all the way around the list - return NULL; - if (rover->tag) - base = rover = rover->next; - else - rover = rover->next; - } while (base->tag || 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->tag = 0; // free block - new->prev = base; - new->id = ZONEID; - new->next = base->next; - new->next->prev = new; - base->next = new; - base->size = size; - } - - base->tag = tag; // no longer a free block - - mainzone->rover = base->next; // next allocation will start looking here - - base->id = ZONEID; - -// marker for memory trash testing - *(int *)((byte *)base + base->size - 4) = ZONEID; - - return (void *) ((byte *)base + sizeof(memblock_t)); -} - - -/* -======================== -Z_Print -======================== -*/ -void Z_Print (memzone_t *zone) -{ - memblock_t *block; - - Con_Printf ("zone size: %i location: %p\n",mainzone->size,mainzone); - - for (block = zone->blocklist.next ; ; block = block->next) - { - Con_Printf ("block:%p size:%7i tag:%3i\n", - block, block->size, block->tag); - - if (block->next == &zone->blocklist) - break; // all blocks have been hit - if ( (byte *)block + block->size != (byte *)block->next) - Con_Printf ("ERROR: block size does not touch the next block\n"); - if ( block->next->prev != block) - Con_Printf ("ERROR: next block doesn't have proper back link\n"); - if (!block->tag && !block->next->tag) - Con_Printf ("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) - Sys_Error ("Z_CheckHeap: block size does not touch the next block\n"); - if ( block->next->prev != block) - Sys_Error ("Z_CheckHeap: next block doesn't have proper back link\n"); - if (!block->tag && !block->next->tag) - Sys_Error ("Z_CheckHeap: two consecutive free blocks\n"); - } -} - -//============================================================================ - -#define HUNK_SENTINAL 0x1df001ed - -typedef struct -{ - int sentinal; - int size; // including sizeof(hunk_t), -1 = not allocated - char name[8]; -} hunk_t; - -byte *hunk_base; -int hunk_size; - -int hunk_low_used; -int hunk_high_used; - -qboolean hunk_tempactive; -int hunk_tempmark; - -void R_FreeTextures (void); - -/* -============== -Hunk_Check - -Run consistancy and sentinal trahing checks -============== -*/ -void Hunk_Check (void) -{ - hunk_t *h; - - for (h = (hunk_t *)hunk_base ; (byte *)h != hunk_base + hunk_low_used ; ) - { - if (h->sentinal != HUNK_SENTINAL) - Sys_Error ("Hunk_Check: trahsed sentinal"); - if (h->size < 16 || h->size + (byte *)h - hunk_base > hunk_size) - Sys_Error ("Hunk_Check: bad size"); - h = (hunk_t *)((byte *)h+h->size); - } -} - -/* -============== -Hunk_Print - -If "all" is specified, every single allocation is printed. -Otherwise, allocations with the same name will be totaled up before printing. -============== -*/ -void Hunk_Print (qboolean all) -{ - hunk_t *h, *next, *endlow, *starthigh, *endhigh; - int count, sum; - int totalblocks; - char name[9]; - - name[8] = 0; - count = 0; - sum = 0; - totalblocks = 0; - - h = (hunk_t *)hunk_base; - endlow = (hunk_t *)(hunk_base + hunk_low_used); - starthigh = (hunk_t *)(hunk_base + hunk_size - hunk_high_used); - endhigh = (hunk_t *)(hunk_base + hunk_size); - - Con_Printf (" :%8i total hunk size\n", hunk_size); - Con_Printf ("-------------------------\n"); - - while (1) - { - // - // skip to the high hunk if done with low hunk - // - if ( h == endlow ) - { - Con_Printf ("-------------------------\n"); - Con_Printf (" :%8i REMAINING\n", hunk_size - hunk_low_used - hunk_high_used); - Con_Printf ("-------------------------\n"); - h = starthigh; - } - - // - // if totally done, break - // - if ( h == endhigh ) - break; - - // - // run consistancy checks - // - if (h->sentinal != HUNK_SENTINAL) - Sys_Error ("Hunk_Check: trahsed sentinal"); - if (h->size < 16 || h->size + (byte *)h - hunk_base > hunk_size) - Sys_Error ("Hunk_Check: bad size"); - - next = (hunk_t *)((byte *)h+h->size); - count++; - totalblocks++; - sum += h->size; - - // - // print the single block - // - memcpy (name, h->name, 8); - if (all) - Con_Printf ("%8p :%8i %8s\n",h, h->size, name); - - // - // print the total - // - if (next == endlow || next == endhigh || - strncmp (h->name, next->name, 8) ) - { - if (!all) - Con_Printf (" :%8i %8s (TOTAL)\n",sum, name); - count = 0; - sum = 0; - } - - h = next; - } - - Con_Printf ("-------------------------\n"); - Con_Printf ("%8i total blocks\n", totalblocks); - -} - -/* -=================== -Hunk_AllocName -=================== -*/ -void *Hunk_AllocName (int size, char *name) -{ - hunk_t *h; - -#ifdef PARANOID - Hunk_Check (); -#endif - - if (size < 0) - Sys_Error ("Hunk_Alloc: bad size: %i", size); - - size = sizeof(hunk_t) + ((size+15)&~15); - - if (hunk_size - hunk_low_used - hunk_high_used < size) - Sys_Error ("Hunk_Alloc: failed on %i bytes",size); - - h = (hunk_t *)(hunk_base + hunk_low_used); - hunk_low_used += size; - - Cache_FreeLow (hunk_low_used); - - memset (h, 0, size); - - h->size = size; - h->sentinal = HUNK_SENTINAL; - Q_strncpy (h->name, name, 8); - - return (void *)(h+1); -} - -/* -=================== -Hunk_Alloc -=================== -*/ -void *Hunk_Alloc (int size) -{ - return Hunk_AllocName (size, "unknown"); -} - -int Hunk_LowMark (void) -{ - return hunk_low_used; -} - -void Hunk_FreeToLowMark (int mark) -{ - if (mark < 0 || mark > hunk_low_used) - Sys_Error ("Hunk_FreeToLowMark: bad mark %i", mark); - memset (hunk_base + mark, 0, hunk_low_used - mark); - hunk_low_used = mark; -} - -int Hunk_HighMark (void) -{ - if (hunk_tempactive) - { - hunk_tempactive = false; - Hunk_FreeToHighMark (hunk_tempmark); - } - - return hunk_high_used; -} - -void Hunk_FreeToHighMark (int mark) -{ - if (hunk_tempactive) - { - hunk_tempactive = false; - Hunk_FreeToHighMark (hunk_tempmark); - } - if (mark < 0 || mark > hunk_high_used) - Sys_Error ("Hunk_FreeToHighMark: bad mark %i", mark); - memset (hunk_base + hunk_size - hunk_high_used, 0, hunk_high_used - mark); - hunk_high_used = mark; -} - - -/* -=================== -Hunk_HighAllocName -=================== -*/ -void *Hunk_HighAllocName (int size, char *name) -{ - hunk_t *h; - - if (size < 0) - Sys_Error ("Hunk_HighAllocName: bad size: %i", size); - - if (hunk_tempactive) - { - Hunk_FreeToHighMark (hunk_tempmark); - hunk_tempactive = false; - } - -#ifdef PARANOID - Hunk_Check (); -#endif - - size = sizeof(hunk_t) + ((size+15)&~15); - - if (hunk_size - hunk_low_used - hunk_high_used < size) - { - Con_Printf ("Hunk_HighAlloc: failed on %i bytes\n",size); - return NULL; - } - - hunk_high_used += size; - Cache_FreeHigh (hunk_high_used); - - h = (hunk_t *)(hunk_base + hunk_size - hunk_high_used); - - memset (h, 0, size); - h->size = size; - h->sentinal = HUNK_SENTINAL; - Q_strncpy (h->name, name, 8); - - return (void *)(h+1); -} - - -/* -================= -Hunk_TempAlloc - -Return space from the top of the hunk -================= -*/ -void *Hunk_TempAlloc (int size) -{ - void *buf; - - size = (size+15)&~15; - - if (hunk_tempactive) - { - Hunk_FreeToHighMark (hunk_tempmark); - hunk_tempactive = false; - } - - hunk_tempmark = Hunk_HighMark (); - - buf = Hunk_HighAllocName (size, "temp"); - - hunk_tempactive = true; - - return buf; -} - -/* -=============================================================================== - -CACHE MEMORY - -=============================================================================== -*/ - -typedef struct cache_system_s -{ - int size; // including this header - cache_user_t *user; - char name[16]; - struct cache_system_s *prev, *next; - struct cache_system_s *lru_prev, *lru_next; // for LRU flushing -} cache_system_t; - -cache_system_t *Cache_TryAlloc (int size, qboolean nobottom); - -cache_system_t cache_head; - -/* -=========== -Cache_Move -=========== -*/ -void Cache_Move ( cache_system_t *c) -{ - cache_system_t *new; - -// we are clearing up space at the bottom, so only allocate it late - new = Cache_TryAlloc (c->size, true); - if (new) - { -// Con_Printf ("cache_move ok\n"); - - Q_memcpy ( new+1, c+1, c->size - sizeof(cache_system_t) ); - new->user = c->user; - Q_memcpy (new->name, c->name, sizeof(new->name)); - Cache_Free (c->user); - new->user->data = (void *)(new+1); - } - else - { -// Con_Printf ("cache_move failed\n"); - - Cache_Free (c->user); // tough luck... - } -} - -/* -============ -Cache_FreeLow - -Throw things out until the hunk can be expanded to the given point -============ -*/ -void Cache_FreeLow (int new_low_hunk) -{ - cache_system_t *c; - - while (1) - { - c = cache_head.next; - if (c == &cache_head) - return; // nothing in cache at all - if ((byte *)c >= hunk_base + new_low_hunk) - return; // there is space to grow the hunk - Cache_Move ( c ); // reclaim the space - } -} - -/* -============ -Cache_FreeHigh - -Throw things out until the hunk can be expanded to the given point -============ -*/ -void Cache_FreeHigh (int new_high_hunk) -{ - cache_system_t *c, *prev; - - prev = NULL; - while (1) - { - c = cache_head.prev; - if (c == &cache_head) - return; // nothing in cache at all - if ( (byte *)c + c->size <= hunk_base + hunk_size - new_high_hunk) - return; // there is space to grow the hunk - if (c == prev) - Cache_Free (c->user); // didn't move out of the way - else - { - Cache_Move (c); // try to move it - prev = c; - } - } -} - -void Cache_UnlinkLRU (cache_system_t *cs) -{ - if (!cs->lru_next || !cs->lru_prev) - Sys_Error ("Cache_UnlinkLRU: NULL link"); - - cs->lru_next->lru_prev = cs->lru_prev; - cs->lru_prev->lru_next = cs->lru_next; - - cs->lru_prev = cs->lru_next = NULL; -} - -void Cache_MakeLRU (cache_system_t *cs) -{ - if (cs->lru_next || cs->lru_prev) - Sys_Error ("Cache_MakeLRU: active link"); - - cache_head.lru_next->lru_prev = cs; - cs->lru_next = cache_head.lru_next; - cs->lru_prev = &cache_head; - cache_head.lru_next = cs; -} - -/* -============ -Cache_TryAlloc - -Looks for a free block of memory between the high and low hunk marks -Size should already include the header and padding -============ -*/ -cache_system_t *Cache_TryAlloc (int size, qboolean nobottom) -{ - cache_system_t *cs, *new; - -// is the cache completely empty? - - if (!nobottom && cache_head.prev == &cache_head) - { - if (hunk_size - hunk_high_used - hunk_low_used < size) - Sys_Error ("Cache_TryAlloc: %i is greater then free hunk", size); - - new = (cache_system_t *) (hunk_base + hunk_low_used); - memset (new, 0, sizeof(*new)); - new->size = size; - - cache_head.prev = cache_head.next = new; - new->prev = new->next = &cache_head; - - Cache_MakeLRU (new); - return new; - } - -// search from the bottom up for space - - new = (cache_system_t *) (hunk_base + hunk_low_used); - cs = cache_head.next; - - do - { - if (!nobottom || cs != cache_head.next) - { - if ( (byte *)cs - (byte *)new >= size) - { // found space - memset (new, 0, sizeof(*new)); - new->size = size; - - new->next = cs; - new->prev = cs->prev; - cs->prev->next = new; - cs->prev = new; - - Cache_MakeLRU (new); - - return new; - } - } - - // continue looking - new = (cache_system_t *)((byte *)cs + cs->size); - cs = cs->next; - - } while (cs != &cache_head); - -// try to allocate one at the very end - if ( hunk_base + hunk_size - hunk_high_used - (byte *)new >= size) - { - memset (new, 0, sizeof(*new)); - new->size = size; - - new->next = &cache_head; - new->prev = cache_head.prev; - cache_head.prev->next = new; - cache_head.prev = new; - - Cache_MakeLRU (new); - - return new; - } - - return NULL; // couldn't allocate -} - -/* -============ -Cache_Flush - -Throw everything out, so new data will be demand cached -============ -*/ -void Cache_Flush (void) -{ - while (cache_head.next != &cache_head) - Cache_Free ( cache_head.next->user ); // reclaim the space -} - - -/* -============ -Cache_Print - -============ -*/ -void Cache_Print (void) -{ - cache_system_t *cd; - - for (cd = cache_head.next ; cd != &cache_head ; cd = cd->next) - { - Con_Printf ("%8i : %s\n", cd->size, cd->name); - } -} - -/* -============ -Cache_Report - -============ -*/ -void Cache_Report (void) -{ - Con_DPrintf ("%4.1f megabyte data cache\n", (hunk_size - hunk_high_used - hunk_low_used) / (float)(1024*1024) ); -} - -/* -============ -Cache_Compact - -============ -*/ -void Cache_Compact (void) -{ -} - -/* -============ -Cache_Init - -============ -*/ -void Cache_Init (void) -{ - cache_head.next = cache_head.prev = &cache_head; - cache_head.lru_next = cache_head.lru_prev = &cache_head; - - Cmd_AddCommand ("flush", Cache_Flush); -} - -/* -============== -Cache_Free - -Frees the memory and removes it from the LRU list -============== -*/ -void Cache_Free (cache_user_t *c) -{ - cache_system_t *cs; - - if (!c->data) - Sys_Error ("Cache_Free: not allocated"); - - cs = ((cache_system_t *)c->data) - 1; - - cs->prev->next = cs->next; - cs->next->prev = cs->prev; - cs->next = cs->prev = NULL; - - c->data = NULL; - - Cache_UnlinkLRU (cs); -} - - - -/* -============== -Cache_Check -============== -*/ -void *Cache_Check (cache_user_t *c) -{ - cache_system_t *cs; - - if (!c->data) - return NULL; - - cs = ((cache_system_t *)c->data) - 1; - -// move to head of LRU - Cache_UnlinkLRU (cs); - Cache_MakeLRU (cs); - - return c->data; -} - - -/* -============== -Cache_Alloc -============== -*/ -void *Cache_Alloc (cache_user_t *c, int size, char *name) -{ - cache_system_t *cs; - - if (c->data) - Sys_Error ("Cache_Alloc: allready allocated"); - - if (size <= 0) - Sys_Error ("Cache_Alloc: size %i", size); - - size = (size + sizeof(cache_system_t) + 15) & ~15; - -// find memory for it - while (1) - { - cs = Cache_TryAlloc (size, false); - if (cs) - { - strncpy (cs->name, name, sizeof(cs->name)-1); - c->data = (void *)(cs+1); - cs->user = c; - break; - } - - // free the least recently used cahedat - if (cache_head.lru_prev == &cache_head) - Sys_Error ("Cache_Alloc: out of memory"); - // not enough memory at all - Cache_Free ( cache_head.lru_prev->user ); - } - - return Cache_Check (c); -} - -//============================================================================ - - -/* -======================== -Memory_Init -======================== -*/ -void Memory_Init (void *buf, int size) -{ - int p; - int zonesize = DYNAMIC_SIZE; - - hunk_base = buf; - hunk_size = size; - hunk_low_used = 0; - hunk_high_used = 0; - - Cache_Init (); - p = COM_CheckParm ("-zone"); - if (p) - { - if (p < com_argc-1) - zonesize = Q_atoi (com_argv[p+1]) * 1024; - else - Sys_Error ("Memory_Init: you must specify a size in KB after -zone"); - } - mainzone = Hunk_AllocName (zonesize, "zone" ); - Z_ClearZone (mainzone, zonesize); -} - +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// Z_zone.c + +#include "quakedef.h" + +#define DYNAMIC_SIZE 0xc000 + +#define ZONEID 0x1d4a11 +#define MINFRAGMENT 64 + +typedef struct memblock_s +{ + int size; // including the header and possibly tiny fragments + int tag; // a tag of 0 is a free block + int id; // should be ZONEID + struct memblock_s *next, *prev; + int pad; // pad to 64 bit boundary +} memblock_t; + +typedef struct +{ + int size; // total bytes malloced, including header + memblock_t blocklist; // start / end cap for linked list + memblock_t *rover; +} memzone_t; + +void Cache_FreeLow (int new_low_hunk); +void Cache_FreeHigh (int new_high_hunk); + + +/* +============================================================================== + + 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 + +The zone calls are pretty much only used for small strings and structures, +all big things are allocated on the hunk. +============================================================================== +*/ + +memzone_t *mainzone; + +void Z_ClearZone (memzone_t *zone, int size); + + +/* +======================== +Z_ClearZone +======================== +*/ +void Z_ClearZone (memzone_t *zone, int size) +{ + 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.tag = 1; // in use block + zone->blocklist.id = 0; + zone->blocklist.size = 0; + zone->rover = block; + + block->prev = block->next = &zone->blocklist; + block->tag = 0; // free block + block->id = ZONEID; + block->size = size - sizeof(memzone_t); +} + + +/* +======================== +Z_Free +======================== +*/ +void Z_Free (void *ptr) +{ + memblock_t *block, *other; + + if (!ptr) + Sys_Error ("Z_Free: NULL pointer"); + + block = (memblock_t *) ( (byte *)ptr - sizeof(memblock_t)); + if (block->id != ZONEID) + Sys_Error ("Z_Free: freed a pointer without ZONEID"); + if (block->tag == 0) + Sys_Error ("Z_Free: freed a freed pointer"); + + block->tag = 0; // mark as free + + other = block->prev; + if (!other->tag) + { // 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->tag) + { // 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 +======================== +*/ +void *Z_Malloc (int size) +{ + void *buf; + +Z_CheckHeap (); // DEBUG + buf = Z_TagMalloc (size, 1); + if (!buf) + Sys_Error ("Z_Malloc: failed on allocation of %i bytes",size); + Q_memset (buf, 0, size); + + return buf; +} + +void *Z_TagMalloc (int size, int tag) +{ + int extra; + memblock_t *start, *rover, *new, *base; + + if (!tag) + Sys_Error ("Z_TagMalloc: tried to use a 0 tag"); + +// +// scan through the block list looking for the first free block +// of sufficient size +// + size += sizeof(memblock_t); // account for size of block header + size += 4; // space for memory trash tester + size = (size + 7) & ~7; // align to 8-byte boundary + + base = rover = mainzone->rover; + start = base->prev; + + do + { + if (rover == start) // scaned all the way around the list + return NULL; + if (rover->tag) + base = rover = rover->next; + else + rover = rover->next; + } while (base->tag || 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->tag = 0; // free block + new->prev = base; + new->id = ZONEID; + new->next = base->next; + new->next->prev = new; + base->next = new; + base->size = size; + } + + base->tag = tag; // no longer a free block + + mainzone->rover = base->next; // next allocation will start looking here + + base->id = ZONEID; + +// marker for memory trash testing + *(int *)((byte *)base + base->size - 4) = ZONEID; + + return (void *) ((byte *)base + sizeof(memblock_t)); +} + + +/* +======================== +Z_Print +======================== +*/ +void Z_Print (memzone_t *zone) +{ + memblock_t *block; + + Con_Printf ("zone size: %i location: %p\n",mainzone->size,mainzone); + + for (block = zone->blocklist.next ; ; block = block->next) + { + Con_Printf ("block:%p size:%7i tag:%3i\n", + block, block->size, block->tag); + + if (block->next == &zone->blocklist) + break; // all blocks have been hit + if ( (byte *)block + block->size != (byte *)block->next) + Con_Printf ("ERROR: block size does not touch the next block\n"); + if ( block->next->prev != block) + Con_Printf ("ERROR: next block doesn't have proper back link\n"); + if (!block->tag && !block->next->tag) + Con_Printf ("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) + Sys_Error ("Z_CheckHeap: block size does not touch the next block\n"); + if ( block->next->prev != block) + Sys_Error ("Z_CheckHeap: next block doesn't have proper back link\n"); + if (!block->tag && !block->next->tag) + Sys_Error ("Z_CheckHeap: two consecutive free blocks\n"); + } +} + +//============================================================================ + +#define HUNK_SENTINAL 0x1df001ed + +typedef struct +{ + int sentinal; + int size; // including sizeof(hunk_t), -1 = not allocated + char name[8]; +} hunk_t; + +byte *hunk_base; +int hunk_size; + +int hunk_low_used; +int hunk_high_used; + +qboolean hunk_tempactive; +int hunk_tempmark; + +void R_FreeTextures (void); + +/* +============== +Hunk_Check + +Run consistancy and sentinal trahing checks +============== +*/ +void Hunk_Check (void) +{ + hunk_t *h; + + for (h = (hunk_t *)hunk_base ; (byte *)h != hunk_base + hunk_low_used ; ) + { + if (h->sentinal != HUNK_SENTINAL) + Sys_Error ("Hunk_Check: trahsed sentinal"); + if (h->size < 16 || h->size + (byte *)h - hunk_base > hunk_size) + Sys_Error ("Hunk_Check: bad size"); + h = (hunk_t *)((byte *)h+h->size); + } +} + +/* +============== +Hunk_Print + +If "all" is specified, every single allocation is printed. +Otherwise, allocations with the same name will be totaled up before printing. +============== +*/ +void Hunk_Print (qboolean all) +{ + hunk_t *h, *next, *endlow, *starthigh, *endhigh; + int count, sum; + int totalblocks; + char name[9]; + + name[8] = 0; + count = 0; + sum = 0; + totalblocks = 0; + + h = (hunk_t *)hunk_base; + endlow = (hunk_t *)(hunk_base + hunk_low_used); + starthigh = (hunk_t *)(hunk_base + hunk_size - hunk_high_used); + endhigh = (hunk_t *)(hunk_base + hunk_size); + + Con_Printf (" :%8i total hunk size\n", hunk_size); + Con_Printf ("-------------------------\n"); + + while (1) + { + // + // skip to the high hunk if done with low hunk + // + if ( h == endlow ) + { + Con_Printf ("-------------------------\n"); + Con_Printf (" :%8i REMAINING\n", hunk_size - hunk_low_used - hunk_high_used); + Con_Printf ("-------------------------\n"); + h = starthigh; + } + + // + // if totally done, break + // + if ( h == endhigh ) + break; + + // + // run consistancy checks + // + if (h->sentinal != HUNK_SENTINAL) + Sys_Error ("Hunk_Check: trahsed sentinal"); + if (h->size < 16 || h->size + (byte *)h - hunk_base > hunk_size) + Sys_Error ("Hunk_Check: bad size"); + + next = (hunk_t *)((byte *)h+h->size); + count++; + totalblocks++; + sum += h->size; + + // + // print the single block + // + memcpy (name, h->name, 8); + if (all) + Con_Printf ("%8p :%8i %8s\n",h, h->size, name); + + // + // print the total + // + if (next == endlow || next == endhigh || + strncmp (h->name, next->name, 8) ) + { + if (!all) + Con_Printf (" :%8i %8s (TOTAL)\n",sum, name); + count = 0; + sum = 0; + } + + h = next; + } + + Con_Printf ("-------------------------\n"); + Con_Printf ("%8i total blocks\n", totalblocks); + +} + +/* +=================== +Hunk_AllocName +=================== +*/ +void *Hunk_AllocName (int size, char *name) +{ + hunk_t *h; + +#ifdef PARANOID + Hunk_Check (); +#endif + + if (size < 0) + Sys_Error ("Hunk_Alloc: bad size: %i", size); + + size = sizeof(hunk_t) + ((size+15)&~15); + + if (hunk_size - hunk_low_used - hunk_high_used < size) + Sys_Error ("Hunk_Alloc: failed on %i bytes",size); + + h = (hunk_t *)(hunk_base + hunk_low_used); + hunk_low_used += size; + + Cache_FreeLow (hunk_low_used); + + memset (h, 0, size); + + h->size = size; + h->sentinal = HUNK_SENTINAL; + Q_strncpy (h->name, name, 8); + + return (void *)(h+1); +} + +/* +=================== +Hunk_Alloc +=================== +*/ +void *Hunk_Alloc (int size) +{ + return Hunk_AllocName (size, "unknown"); +} + +int Hunk_LowMark (void) +{ + return hunk_low_used; +} + +void Hunk_FreeToLowMark (int mark) +{ + if (mark < 0 || mark > hunk_low_used) + Sys_Error ("Hunk_FreeToLowMark: bad mark %i", mark); + memset (hunk_base + mark, 0, hunk_low_used - mark); + hunk_low_used = mark; +} + +int Hunk_HighMark (void) +{ + if (hunk_tempactive) + { + hunk_tempactive = false; + Hunk_FreeToHighMark (hunk_tempmark); + } + + return hunk_high_used; +} + +void Hunk_FreeToHighMark (int mark) +{ + if (hunk_tempactive) + { + hunk_tempactive = false; + Hunk_FreeToHighMark (hunk_tempmark); + } + if (mark < 0 || mark > hunk_high_used) + Sys_Error ("Hunk_FreeToHighMark: bad mark %i", mark); + memset (hunk_base + hunk_size - hunk_high_used, 0, hunk_high_used - mark); + hunk_high_used = mark; +} + + +/* +=================== +Hunk_HighAllocName +=================== +*/ +void *Hunk_HighAllocName (int size, char *name) +{ + hunk_t *h; + + if (size < 0) + Sys_Error ("Hunk_HighAllocName: bad size: %i", size); + + if (hunk_tempactive) + { + Hunk_FreeToHighMark (hunk_tempmark); + hunk_tempactive = false; + } + +#ifdef PARANOID + Hunk_Check (); +#endif + + size = sizeof(hunk_t) + ((size+15)&~15); + + if (hunk_size - hunk_low_used - hunk_high_used < size) + { + Con_Printf ("Hunk_HighAlloc: failed on %i bytes\n",size); + return NULL; + } + + hunk_high_used += size; + Cache_FreeHigh (hunk_high_used); + + h = (hunk_t *)(hunk_base + hunk_size - hunk_high_used); + + memset (h, 0, size); + h->size = size; + h->sentinal = HUNK_SENTINAL; + Q_strncpy (h->name, name, 8); + + return (void *)(h+1); +} + + +/* +================= +Hunk_TempAlloc + +Return space from the top of the hunk +================= +*/ +void *Hunk_TempAlloc (int size) +{ + void *buf; + + size = (size+15)&~15; + + if (hunk_tempactive) + { + Hunk_FreeToHighMark (hunk_tempmark); + hunk_tempactive = false; + } + + hunk_tempmark = Hunk_HighMark (); + + buf = Hunk_HighAllocName (size, "temp"); + + hunk_tempactive = true; + + return buf; +} + +/* +=============================================================================== + +CACHE MEMORY + +=============================================================================== +*/ + +typedef struct cache_system_s +{ + int size; // including this header + cache_user_t *user; + char name[16]; + struct cache_system_s *prev, *next; + struct cache_system_s *lru_prev, *lru_next; // for LRU flushing +} cache_system_t; + +cache_system_t *Cache_TryAlloc (int size, qboolean nobottom); + +cache_system_t cache_head; + +/* +=========== +Cache_Move +=========== +*/ +void Cache_Move ( cache_system_t *c) +{ + cache_system_t *new; + +// we are clearing up space at the bottom, so only allocate it late + new = Cache_TryAlloc (c->size, true); + if (new) + { +// Con_Printf ("cache_move ok\n"); + + Q_memcpy ( new+1, c+1, c->size - sizeof(cache_system_t) ); + new->user = c->user; + Q_memcpy (new->name, c->name, sizeof(new->name)); + Cache_Free (c->user); + new->user->data = (void *)(new+1); + } + else + { +// Con_Printf ("cache_move failed\n"); + + Cache_Free (c->user); // tough luck... + } +} + +/* +============ +Cache_FreeLow + +Throw things out until the hunk can be expanded to the given point +============ +*/ +void Cache_FreeLow (int new_low_hunk) +{ + cache_system_t *c; + + while (1) + { + c = cache_head.next; + if (c == &cache_head) + return; // nothing in cache at all + if ((byte *)c >= hunk_base + new_low_hunk) + return; // there is space to grow the hunk + Cache_Move ( c ); // reclaim the space + } +} + +/* +============ +Cache_FreeHigh + +Throw things out until the hunk can be expanded to the given point +============ +*/ +void Cache_FreeHigh (int new_high_hunk) +{ + cache_system_t *c, *prev; + + prev = NULL; + while (1) + { + c = cache_head.prev; + if (c == &cache_head) + return; // nothing in cache at all + if ( (byte *)c + c->size <= hunk_base + hunk_size - new_high_hunk) + return; // there is space to grow the hunk + if (c == prev) + Cache_Free (c->user); // didn't move out of the way + else + { + Cache_Move (c); // try to move it + prev = c; + } + } +} + +void Cache_UnlinkLRU (cache_system_t *cs) +{ + if (!cs->lru_next || !cs->lru_prev) + Sys_Error ("Cache_UnlinkLRU: NULL link"); + + cs->lru_next->lru_prev = cs->lru_prev; + cs->lru_prev->lru_next = cs->lru_next; + + cs->lru_prev = cs->lru_next = NULL; +} + +void Cache_MakeLRU (cache_system_t *cs) +{ + if (cs->lru_next || cs->lru_prev) + Sys_Error ("Cache_MakeLRU: active link"); + + cache_head.lru_next->lru_prev = cs; + cs->lru_next = cache_head.lru_next; + cs->lru_prev = &cache_head; + cache_head.lru_next = cs; +} + +/* +============ +Cache_TryAlloc + +Looks for a free block of memory between the high and low hunk marks +Size should already include the header and padding +============ +*/ +cache_system_t *Cache_TryAlloc (int size, qboolean nobottom) +{ + cache_system_t *cs, *new; + +// is the cache completely empty? + + if (!nobottom && cache_head.prev == &cache_head) + { + if (hunk_size - hunk_high_used - hunk_low_used < size) + Sys_Error ("Cache_TryAlloc: %i is greater then free hunk", size); + + new = (cache_system_t *) (hunk_base + hunk_low_used); + memset (new, 0, sizeof(*new)); + new->size = size; + + cache_head.prev = cache_head.next = new; + new->prev = new->next = &cache_head; + + Cache_MakeLRU (new); + return new; + } + +// search from the bottom up for space + + new = (cache_system_t *) (hunk_base + hunk_low_used); + cs = cache_head.next; + + do + { + if (!nobottom || cs != cache_head.next) + { + if ( (byte *)cs - (byte *)new >= size) + { // found space + memset (new, 0, sizeof(*new)); + new->size = size; + + new->next = cs; + new->prev = cs->prev; + cs->prev->next = new; + cs->prev = new; + + Cache_MakeLRU (new); + + return new; + } + } + + // continue looking + new = (cache_system_t *)((byte *)cs + cs->size); + cs = cs->next; + + } while (cs != &cache_head); + +// try to allocate one at the very end + if ( hunk_base + hunk_size - hunk_high_used - (byte *)new >= size) + { + memset (new, 0, sizeof(*new)); + new->size = size; + + new->next = &cache_head; + new->prev = cache_head.prev; + cache_head.prev->next = new; + cache_head.prev = new; + + Cache_MakeLRU (new); + + return new; + } + + return NULL; // couldn't allocate +} + +/* +============ +Cache_Flush + +Throw everything out, so new data will be demand cached +============ +*/ +void Cache_Flush (void) +{ + while (cache_head.next != &cache_head) + Cache_Free ( cache_head.next->user ); // reclaim the space +} + + +/* +============ +Cache_Print + +============ +*/ +void Cache_Print (void) +{ + cache_system_t *cd; + + for (cd = cache_head.next ; cd != &cache_head ; cd = cd->next) + { + Con_Printf ("%8i : %s\n", cd->size, cd->name); + } +} + +/* +============ +Cache_Report + +============ +*/ +void Cache_Report (void) +{ + Con_DPrintf ("%4.1f megabyte data cache\n", (hunk_size - hunk_high_used - hunk_low_used) / (float)(1024*1024) ); +} + +/* +============ +Cache_Compact + +============ +*/ +void Cache_Compact (void) +{ +} + +/* +============ +Cache_Init + +============ +*/ +void Cache_Init (void) +{ + cache_head.next = cache_head.prev = &cache_head; + cache_head.lru_next = cache_head.lru_prev = &cache_head; + + Cmd_AddCommand ("flush", Cache_Flush); +} + +/* +============== +Cache_Free + +Frees the memory and removes it from the LRU list +============== +*/ +void Cache_Free (cache_user_t *c) +{ + cache_system_t *cs; + + if (!c->data) + Sys_Error ("Cache_Free: not allocated"); + + cs = ((cache_system_t *)c->data) - 1; + + cs->prev->next = cs->next; + cs->next->prev = cs->prev; + cs->next = cs->prev = NULL; + + c->data = NULL; + + Cache_UnlinkLRU (cs); +} + + + +/* +============== +Cache_Check +============== +*/ +void *Cache_Check (cache_user_t *c) +{ + cache_system_t *cs; + + if (!c->data) + return NULL; + + cs = ((cache_system_t *)c->data) - 1; + +// move to head of LRU + Cache_UnlinkLRU (cs); + Cache_MakeLRU (cs); + + return c->data; +} + + +/* +============== +Cache_Alloc +============== +*/ +void *Cache_Alloc (cache_user_t *c, int size, char *name) +{ + cache_system_t *cs; + + if (c->data) + Sys_Error ("Cache_Alloc: allready allocated"); + + if (size <= 0) + Sys_Error ("Cache_Alloc: size %i", size); + + size = (size + sizeof(cache_system_t) + 15) & ~15; + +// find memory for it + while (1) + { + cs = Cache_TryAlloc (size, false); + if (cs) + { + strncpy (cs->name, name, sizeof(cs->name)-1); + c->data = (void *)(cs+1); + cs->user = c; + break; + } + + // free the least recently used cahedat + if (cache_head.lru_prev == &cache_head) + Sys_Error ("Cache_Alloc: out of memory"); + // not enough memory at all + Cache_Free ( cache_head.lru_prev->user ); + } + + return Cache_Check (c); +} + +//============================================================================ + + +/* +======================== +Memory_Init +======================== +*/ +void Memory_Init (void *buf, int size) +{ + int p; + int zonesize = DYNAMIC_SIZE; + + hunk_base = buf; + hunk_size = size; + hunk_low_used = 0; + hunk_high_used = 0; + + Cache_Init (); + p = COM_CheckParm ("-zone"); + if (p) + { + if (p < com_argc-1) + zonesize = Q_atoi (com_argv[p+1]) * 1024; + else + Sys_Error ("Memory_Init: you must specify a size in KB after -zone"); + } + mainzone = Hunk_AllocName (zonesize, "zone" ); + Z_ClearZone (mainzone, zonesize); +} + -- cgit v1.2.3