2004-08-21 01:25:48 +00:00
/*
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"
# ifdef _WIN32
# include "winquake.h"
# endif
# undef malloc
# undef free
# define NOZONE
# define NOCACHE
2004-12-02 06:00:21 +00:00
# ifdef _WIN32
# define NOHIGH
# endif
2004-08-21 01:25:48 +00:00
void Cache_FreeLow ( int new_low_hunk ) ;
void Cache_FreeHigh ( int new_high_hunk ) ;
2004-09-20 23:25:38 +00:00
# ifdef _DEBUG
2004-11-27 08:16:25 +00:00
//#define MEMDEBUG 8192 //Debugging adds sentinels (the number is the size - I have the ram)
2004-09-20 23:25:38 +00:00
# endif
2004-12-03 03:02:17 +00:00
//must be multiple of 4.
# define TEMPDEBUG 4
2005-04-16 16:21:27 +00:00
# define ZONEDEBUG 4
2004-12-03 03:02:17 +00:00
# define HUNKDEBUG 4
2006-01-21 00:06:49 +00:00
# define CACHEDEBUG 4
2004-12-02 06:00:21 +00:00
//these need to be defined because it makes some bits of code simpler
# ifndef HUNKDEBUG
# define HUNKDEBUG 0
# endif
# ifndef ZONEDEBUG
# define ZONEDEBUG 0
# endif
# ifndef TEMPDEBUG
# define TEMPDEBUG 0
# endif
# ifndef CACHEDEBUG
# define CACHEDEBUG 0
2004-09-20 23:25:38 +00:00
# endif
2004-12-02 06:00:21 +00:00
# if ZONEDEBUG>0 || HUNKDEBUG>0 || TEMPDEBUG>0||CACHEDEBUG>0
2004-09-20 23:25:38 +00:00
qbyte sentinalkey ;
# endif
2008-05-09 14:22:37 +00:00
# define TAGLESS 1
2004-08-21 01:25:48 +00:00
2012-05-09 15:30:53 +00:00
int zmemtotal ;
int zmemdelta ;
2008-05-09 14:22:37 +00:00
typedef struct memheader_s {
int size ;
int tag ;
} memheader_t ;
typedef struct zone_s {
struct zone_s * next ;
struct zone_s * pvdn ; // down if first, previous if not
memheader_t mh ;
} zone_t ;
zone_t * zone_head ;
# ifdef MULTITHREAD
void * zonelock ;
# endif
2009-04-02 22:25:54 +00:00
#if 0
2008-11-09 22:29:28 +00:00
static void Z_DumpTree ( void )
2008-09-12 00:17:32 +00:00
{
zone_t * zone ;
zone_t * nextlist ;
zone_t * t ;
zone_t * prev ;
zone = zone_head ;
while ( zone )
{
nextlist = zone - > pvdn ;
fprintf ( stderr , " +-+ %016x (tag: %08x) \n " , zone , zone - > mh . tag ) ;
prev = zone ;
t = zone - > next ;
while ( t )
{
if ( t - > pvdn ! = prev )
fprintf ( stderr , " Previous link failure \n " ) ;
prev = t ;
t = t - > next ;
}
while ( zone )
{
fprintf ( stderr , " +-- %016x \n " , zone ) ;
zone = zone - > next ;
}
zone = nextlist ;
}
}
2009-04-02 22:25:54 +00:00
# endif
2008-09-12 00:17:32 +00:00
2008-05-09 14:22:37 +00:00
void * VARGS Z_TagMalloc ( int size , int tag )
{
zone_t * zone ;
zone = ( zone_t * ) malloc ( size + sizeof ( zone_t ) ) ;
if ( ! zone )
Sys_Error ( " Z_Malloc: Failed on allocation of %i bytes " , size ) ;
Q_memset ( zone , 0 , size + sizeof ( zone_t ) ) ;
zone - > mh . tag = tag ;
zone - > mh . size = size ;
# ifdef MULTITHREAD
if ( zonelock )
Sys_LockMutex ( zonelock ) ;
# endif
2008-09-12 00:17:32 +00:00
#if 0
fprintf ( stderr , " Before alloc: \n " ) ;
Z_DumpTree ( ) ;
fprintf ( stderr , " \n " ) ;
# endif
2008-05-09 14:22:37 +00:00
if ( zone_head = = NULL )
zone_head = zone ;
else
{
2008-09-12 00:17:32 +00:00
zone_t * s = zone_head ;
2008-05-09 14:22:37 +00:00
while ( s & & s - > mh . tag ! = tag )
s = s - > pvdn ;
if ( s )
{ // tag match
zone - > next = s - > next ;
2008-09-12 00:17:32 +00:00
if ( s - > next )
s - > next - > pvdn = zone ;
zone - > pvdn = s ;
2008-05-09 14:22:37 +00:00
s - > next = zone ;
}
else
{
zone - > pvdn = zone_head ;
2009-04-01 22:03:56 +00:00
// if (s->next)
// s->next->pvdn = zone;
2008-05-09 14:22:37 +00:00
zone_head = zone ;
}
}
2008-09-12 00:17:32 +00:00
#if 0
fprintf ( stderr , " After alloc: \n " ) ;
Z_DumpTree ( ) ;
fprintf ( stderr , " \n " ) ;
# endif
2008-05-09 14:22:37 +00:00
# ifdef MULTITHREAD
if ( zonelock )
Sys_UnlockMutex ( zonelock ) ;
# endif
return ( void * ) ( zone + 1 ) ;
}
2012-07-05 19:42:36 +00:00
# ifdef USE_MSVCRT_DEBUG
void * ZF_MallocNamed ( int size , char * file , int line )
{
return _calloc_dbg ( size , 1 , _NORMAL_BLOCK , file , line ) ;
}
void * Z_MallocNamed ( int size , char * file , int line )
{
void * mem = ZF_MallocNamed ( size , file , line ) ;
if ( ! mem )
Sys_Error ( " Z_Malloc: Failed on allocation of %i bytes " , size ) ;
return mem ;
}
# else
2008-05-09 14:22:37 +00:00
void * ZF_Malloc ( int size )
{
return calloc ( size , 1 ) ;
}
void * Z_Malloc ( int size )
{
void * mem = ZF_Malloc ( size ) ;
if ( ! mem )
Sys_Error ( " Z_Malloc: Failed on allocation of %i bytes " , size ) ;
return mem ;
}
2012-07-05 19:42:36 +00:00
# endif
2008-05-09 14:22:37 +00:00
void VARGS Z_TagFree ( void * mem )
{
zone_t * zone = ( ( zone_t * ) mem ) - 1 ;
2008-09-12 00:17:32 +00:00
#if 0
fprintf ( stderr , " Before free: \n " ) ;
Z_DumpTree ( ) ;
fprintf ( stderr , " \n " ) ;
# endif
2008-05-09 14:22:37 +00:00
# ifdef MULTITHREAD
if ( zonelock )
Sys_LockMutex ( zonelock ) ;
# endif
if ( zone - > next )
zone - > next - > pvdn = zone - > pvdn ;
2008-09-12 00:17:32 +00:00
2008-05-09 14:22:37 +00:00
if ( zone - > pvdn & & zone - > pvdn - > mh . tag = = zone - > mh . tag )
zone - > pvdn - > next = zone - > next ;
else
{ // zone is first entry in a tag list
zone_t * s = zone_head ;
if ( zone ! = s )
{ // traverse and update down list
while ( s - > pvdn ! = zone )
2008-09-12 00:17:32 +00:00
s = s - > pvdn ;
2004-08-21 01:25:48 +00:00
2008-09-12 00:17:32 +00:00
if ( zone - > next )
s - > pvdn = zone - > next ;
else
s - > pvdn = zone - > pvdn ;
2008-05-09 14:22:37 +00:00
}
}
if ( zone = = zone_head )
{ // freeing head node so update head pointer
if ( zone - > next ) // move to next, pvdn should be maintained properly
zone_head = zone - > next ;
else // no more entries with this tag so move head down
zone_head = zone - > pvdn ;
}
2008-09-12 00:17:32 +00:00
#if 0
fprintf ( stderr , " After free: \n " ) ;
Z_DumpTree ( ) ;
fprintf ( stderr , " \n " ) ;
# endif
2008-05-09 14:22:37 +00:00
# ifdef MULTITHREAD
if ( zonelock )
Sys_UnlockMutex ( zonelock ) ;
# endif
free ( zone ) ;
}
void VARGS Z_Free ( void * mem )
{
free ( mem ) ;
}
void VARGS Z_FreeTags ( int tag )
{
zone_t * taglist ;
zone_t * t ;
# ifdef MULTITHREAD
if ( zonelock )
Sys_LockMutex ( zonelock ) ;
# endif
if ( zone_head )
{
if ( zone_head - > mh . tag = = tag )
{ // just pull off the head
taglist = zone_head ;
zone_head = zone_head - > pvdn ;
}
else
{ // search for tag list and isolate it
zone_t * z ;
z = zone_head ;
2008-09-18 18:25:39 +00:00
while ( z - > pvdn ! = NULL & & z - > pvdn - > mh . tag ! = tag )
z = z - > pvdn ;
2008-05-09 14:22:37 +00:00
2008-10-08 19:18:12 +00:00
if ( z - > pvdn = = NULL )
2008-05-09 14:22:37 +00:00
taglist = NULL ;
else
{
2008-09-18 18:25:39 +00:00
taglist = z - > pvdn ;
z - > pvdn = z - > pvdn - > pvdn ;
2008-05-09 14:22:37 +00:00
}
}
}
else
taglist = NULL ;
# ifdef MULTITHREAD
if ( zonelock )
Sys_UnlockMutex ( zonelock ) ;
# endif
// actually free list
while ( taglist ! = NULL )
{
t = taglist - > next ;
free ( taglist ) ;
taglist = t ;
}
}
2004-08-21 01:25:48 +00:00
2008-05-09 14:22:37 +00:00
/*
void * Z_Realloc ( void * data , int newsize )
{
memheader_t * memref ;
if ( ! data )
return Z_Malloc ( newsize ) ;
memref = ( ( memheader_t * ) data ) - 1 ;
if ( memref [ 0 ] . tag ! = TAGLESS )
{ // allocate a new block and copy since we need to maintain the lists
zone_t * zone = ( ( zone_t * ) data ) - 1 ;
int size = zone - > mh . size ;
if ( size ! = newsize )
{
void * newdata = Z_Malloc ( newsize ) ;
if ( size > newsize )
size = newsize ;
memcpy ( newdata , data , size ) ;
Z_Free ( data ) ;
data = newdata ;
}
}
else
{
int oldsize = memref [ 0 ] . size ;
memref = realloc ( memref , newsize + sizeof ( memheader_t ) ) ;
memref - > size = newsize ;
if ( newsize > oldsize )
memset ( ( qbyte * ) memref + sizeof ( memheader_t ) + oldsize , 0 , newsize - oldsize ) ;
data = ( ( memheader_t * ) memref ) + 1 ;
}
return data ;
}
*/
2012-07-05 19:42:36 +00:00
# ifdef USE_MSVCRT_DEBUG
void * BZF_MallocNamed ( int size , char * file , int line ) //BZ_MallocNamed but allowed to fail - like straight malloc.
{
void * mem ;
mem = _malloc_dbg ( size , _NORMAL_BLOCK , file , line ) ;
if ( mem )
{
zmemdelta + = size ;
zmemtotal + = size ;
}
return mem ;
}
# else
2008-05-09 14:22:37 +00:00
void * BZF_Malloc ( int size ) //BZ_Malloc but allowed to fail - like straight malloc.
{
2012-05-09 15:30:53 +00:00
void * mem ;
mem = malloc ( size ) ;
if ( mem )
{
zmemdelta + = size ;
zmemtotal + = size ;
}
return mem ;
2008-05-09 14:22:37 +00:00
}
2012-07-05 19:42:36 +00:00
# endif
2008-05-09 14:22:37 +00:00
2012-07-05 19:42:36 +00:00
# ifdef USE_MSVCRT_DEBUG
void * BZ_MallocNamed ( int size , char * file , int line ) //BZ_MallocNamed but allowed to fail - like straight malloc.
{
void * mem = BZF_MallocNamed ( size , file , line ) ;
if ( ! mem )
Sys_Error ( " BZ_Malloc: Failed on allocation of %i bytes " , size ) ;
return mem ;
}
# else
2008-05-09 14:22:37 +00:00
void * BZ_Malloc ( int size ) //Doesn't clear. The expectation is a large file, rather than sensative data structures.
{
void * mem = BZF_Malloc ( size ) ;
if ( ! mem )
Sys_Error ( " BZ_Malloc: Failed on allocation of %i bytes " , size ) ;
return mem ;
}
2012-07-05 19:42:36 +00:00
# endif
# ifdef USE_MSVCRT_DEBUG
void * BZF_ReallocNamed ( void * data , int newsize , char * file , int line )
{
return _realloc_dbg ( data , newsize , _NORMAL_BLOCK , file , line ) ;
}
2008-05-09 14:22:37 +00:00
2012-07-05 19:42:36 +00:00
void * BZ_ReallocNamed ( void * data , int newsize , char * file , int line )
{
void * mem = BZF_ReallocNamed ( data , newsize , file , line ) ;
if ( ! mem )
Sys_Error ( " BZ_Realloc: Failed on reallocation of %i bytes " , newsize ) ;
return mem ;
}
# else
2008-05-09 14:22:37 +00:00
void * BZF_Realloc ( void * data , int newsize )
{
return realloc ( data , newsize ) ;
}
void * BZ_Realloc ( void * data , int newsize )
{
void * mem = BZF_Realloc ( data , newsize ) ;
if ( ! mem )
Sys_Error ( " BZ_Realloc: Failed on reallocation of %i bytes " , newsize ) ;
return mem ;
}
2012-07-05 19:42:36 +00:00
# endif
2008-05-09 14:22:37 +00:00
void BZ_Free ( void * data )
{
free ( data ) ;
}
#if 0 //NOZONE //zone memory is for small dynamic things.
2004-08-21 01:25:48 +00:00
/*
void * Z_TagMalloc ( int size , int tag )
{
return malloc ( size ) ;
}
void * Z_Malloc ( int size )
{
qbyte * buf ;
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_Free ( void * buf )
{
free ( buf ) ;
}
void Z_FreeTags ( void * buf )
{
free ( buf ) ;
}
*/
# define ZONEID 0x1d4a11
# define ZONESENTINAL 0xdeadbeaf
typedef struct zone_s {
// int sentinal1;
struct zone_s * next ;
struct zone_s * prev ;
int size ;
int tag ;
// int sentinal2;
} zone_t ;
zone_t * zone_head ;
/*
void Z_CheckSentinals ( void )
{
zone_t * zone ;
for ( zone = zone_head ; zone ; zone = zone - > next )
{
if ( zone - > sentinal1 ! = ZONESENTINAL | | zone - > sentinal2 ! = ZONESENTINAL )
Sys_Error ( " Memory sentinal destroyed \n " ) ;
}
} */
2005-09-08 22:52:46 +00:00
2005-03-18 06:13:36 +00:00
void VARGS Z_Free ( void * c )
2004-08-21 01:25:48 +00:00
{
zone_t * nz ;
2004-12-02 06:00:21 +00:00
nz = ( ( zone_t * ) ( ( char * ) c - ZONEDEBUG ) ) - 1 ;
2004-08-21 01:25:48 +00:00
// Z_CheckSentinals();
2004-12-02 06:00:21 +00:00
# if ZONEDEBUG>0
2004-09-20 23:25:38 +00:00
{
int i ;
qbyte * buf ;
buf = ( qbyte * ) ( nz + 1 ) ;
2004-12-02 06:00:21 +00:00
for ( i = 0 ; i < ZONEDEBUG ; i + + )
2004-09-20 23:25:38 +00:00
{
if ( buf [ i ] ! = sentinalkey )
2006-01-02 22:57:18 +00:00
Sys_Error ( " corrupt memory block (%i? bytes) \n " , nz - > size ) ;
2004-09-20 23:25:38 +00:00
}
2004-12-02 06:00:21 +00:00
buf + = ZONEDEBUG ;
2004-09-20 23:25:38 +00:00
//app data
buf + = nz - > size ;
2004-12-02 06:00:21 +00:00
for ( i = 0 ; i < ZONEDEBUG ; i + + )
2004-09-20 23:25:38 +00:00
{
if ( buf [ i ] ! = sentinalkey )
2006-01-02 22:57:18 +00:00
Sys_Error ( " corrupt memory block (%i? bytes) \n " , nz - > size ) ;
2004-09-20 23:25:38 +00:00
}
}
# endif
2004-08-21 01:25:48 +00:00
// if (nz->sentinal1 != ZONESENTINAL || nz->sentinal2 != ZONESENTINAL)
// Sys_Error("zone was not z_malloced\n");
if ( nz - > next )
nz - > next - > prev = nz - > prev ;
if ( nz - > prev )
nz - > prev - > next = nz - > next ;
if ( nz = = zone_head )
zone_head = nz - > next ;
2005-10-01 03:09:17 +00:00
// Con_Printf("Free of %i bytes\n", nz->size);
2004-08-21 01:25:48 +00:00
free ( nz ) ;
}
2004-11-23 00:31:46 +00:00
void BZ_CheckSentinals ( void * c )
{
2004-12-02 06:00:21 +00:00
# if ZONEDEBUG>0
2004-11-23 00:31:46 +00:00
zone_t * nz ;
2004-12-02 06:00:21 +00:00
nz = ( ( zone_t * ) ( ( char * ) c - ZONEDEBUG ) ) - 1 ;
2004-11-23 00:31:46 +00:00
// Z_CheckSentinals();
{
int i ;
qbyte * buf ;
buf = ( qbyte * ) ( nz + 1 ) ;
2004-12-02 06:00:21 +00:00
for ( i = 0 ; i < ZONEDEBUG ; i + + )
2004-11-23 00:31:46 +00:00
{
if ( buf [ i ] ! = sentinalkey )
2006-01-02 22:57:18 +00:00
Sys_Error ( " corrupt memory block (%i? bytes) \n " , nz - > size ) ;
2004-11-23 00:31:46 +00:00
}
2004-12-02 06:00:21 +00:00
buf + = ZONEDEBUG ;
2004-11-23 00:31:46 +00:00
//app data
buf + = nz - > size ;
2004-12-02 06:00:21 +00:00
for ( i = 0 ; i < ZONEDEBUG ; i + + )
2004-11-23 00:31:46 +00:00
{
if ( buf [ i ] ! = sentinalkey )
2006-01-02 22:57:18 +00:00
Sys_Error ( " corrupt memory block (%i? bytes) \n " , nz - > size ) ;
2004-11-23 00:31:46 +00:00
}
}
# endif
}
2005-03-28 07:05:38 +00:00
//revive this function each time you get memory corruption and need to trace it.
2005-03-18 06:13:36 +00:00
void BZ_CheckAllSentinals ( void )
{
zone_t * zone ;
for ( zone = zone_head ; zone ; zone = zone - > next )
{
int i ;
qbyte * buf ;
buf = ( qbyte * ) ( zone + 1 ) ;
for ( i = 0 ; i < ZONEDEBUG ; i + + )
{
if ( buf [ i ] ! = sentinalkey )
2006-01-02 22:57:18 +00:00
Sys_Error ( " corrupt memory block (%i? bytes) \n " , zone - > size ) ;
2005-03-18 06:13:36 +00:00
}
buf + = ZONEDEBUG ;
//app data
buf + = zone - > size ;
for ( i = 0 ; i < ZONEDEBUG ; i + + )
{
if ( buf [ i ] ! = sentinalkey )
2006-01-02 22:57:18 +00:00
Sys_Error ( " corrupt memory block (%i? bytes) \n " , zone - > size ) ;
2005-03-18 06:13:36 +00:00
}
}
}
2005-03-28 07:05:38 +00:00
2004-11-23 00:31:46 +00:00
2005-03-18 06:13:36 +00:00
void VARGS Z_FreeTags ( int tag )
2004-08-21 01:25:48 +00:00
{
zone_t * zone , * next ;
for ( zone = zone_head ; zone ; zone = next )
{
next = zone - > next ;
if ( zone - > tag = = tag )
2004-12-02 06:00:21 +00:00
Z_Free ( ( char * ) ( zone + 1 ) + ZONEDEBUG ) ;
2004-08-21 01:25:48 +00:00
}
}
# ifdef NAMEDMALLOCS
void * Z_BaseTagMalloc ( int size , int tag , qboolean clear , char * descrip , . . . )
# else
void * Z_BaseTagMalloc ( int size , int tag , qboolean clear )
# endif
{
# ifdef NAMEDMALLOCS
va_list argptr ;
char buffer [ 512 ] ;
# endif
void * buf ;
zone_t * nt ;
// Z_CheckSentinals();
2005-10-01 03:09:17 +00:00
//Con_Printf("Malloc of %i bytes\n", size);
//if (size>20)
//Con_Printf("Big malloc\n");
2004-08-21 01:25:48 +00:00
if ( size < = 0 )
Sys_Error ( " Z_Malloc: size %i " , size ) ;
# ifdef NAMEDMALLOCS
va_start ( argptr , descrip ) ;
vsprintf ( buffer , descrip , argptr ) ;
va_end ( argptr ) ;
2005-03-28 00:11:59 +00:00
nt = ( zone_t * ) malloc ( size + sizeof ( zone_t ) + strlen ( buffer ) + 1 + ZONEDEBUG * 2 ) ;
2004-08-21 01:25:48 +00:00
# else
2005-03-28 00:11:59 +00:00
nt = ( zone_t * ) malloc ( size + sizeof ( zone_t ) + ZONEDEBUG * 2 ) ;
2004-08-21 01:25:48 +00:00
# endif
if ( ! nt )
Sys_Error ( " Z_BaseTagMalloc: failed on allocation of %i bytes " , size ) ;
nt - > next = zone_head ;
nt - > prev = NULL ;
nt - > size = size ;
nt - > tag = tag ;
// nt->sentinal1 = ZONESENTINAL;
// nt->sentinal2 = ZONESENTINAL;
if ( zone_head )
zone_head - > prev = nt ;
zone_head = nt ;
buf = ( void * ) ( nt + 1 ) ;
2004-09-20 23:25:38 +00:00
2004-12-02 06:00:21 +00:00
# if ZONEDEBUG > 0
memset ( buf , sentinalkey , ZONEDEBUG ) ;
buf = ( char * ) buf + ZONEDEBUG ;
memset ( ( char * ) buf + size , sentinalkey , ZONEDEBUG ) ;
2004-09-20 23:25:38 +00:00
# endif
2004-08-21 01:25:48 +00:00
if ( clear )
Q_memset ( buf , 0 , size ) ;
# ifdef NAMEDMALLOCS
2004-12-02 06:00:21 +00:00
strcpy ( ( char * ) ( nt + 1 ) + nt - > size + ZONEDEBUG * 2 , buffer ) ;
2004-08-21 01:25:48 +00:00
# endif
return buf ;
}
2005-03-18 06:13:36 +00:00
void * VARGS Z_TagMalloc ( int size , int tag )
2004-08-21 01:25:48 +00:00
{
# ifdef NAMEDMALLOCS
return Z_BaseTagMalloc ( size , tag , true , " " ) ;
# else
return Z_BaseTagMalloc ( size , tag , true ) ;
# endif
}
# ifdef NAMEDMALLOCS
void * Z_MallocNamed ( int size , char * file , int lineno )
{
qbyte * buf ;
buf = Z_BaseTagMalloc ( size , 1 , true , " %s: %i " , file , lineno ) ;
if ( ! buf )
Sys_Error ( " Z_Malloc: Failed on allocation of %i bytes " , size ) ;
return buf ;
}
# else
void * Z_Malloc ( int size )
{
qbyte * buf ;
2005-03-28 00:11:59 +00:00
buf = ( qbyte * ) Z_TagMalloc ( size , 1 ) ;
2004-08-21 01:25:48 +00:00
if ( ! buf )
Sys_Error ( " Z_Malloc: Failed on allocation of %i bytes " , size ) ;
return buf ;
}
void * BZ_Malloc ( int size ) //Doesn't clear. The expectation is a large file, rather than sensative data structures.
{
void * data = Z_BaseTagMalloc ( size , 1 , true ) ;
if ( ! data )
Sys_Error ( " BZ_Malloc failed on %i bytes " , size ) ;
return data ;
}
# endif
void * BZF_Malloc ( int size ) //BZ_Malloc but allowed to fail - like straight malloc.
{
# ifdef NAMEDMALLOCS
return Z_BaseTagMalloc ( size , 1 , false , " " ) ;
# else
return Z_BaseTagMalloc ( size , 1 , false ) ;
# endif
}
2004-10-03 22:52:02 +00:00
# ifdef NAMEDMALLOCS
void * BZ_NamedRealloc ( void * data , int newsize , char * file , int lineno )
# else
2004-08-21 01:25:48 +00:00
void * BZ_Realloc ( void * data , int newsize )
2004-10-03 22:52:02 +00:00
# endif
2004-08-21 01:25:48 +00:00
{
zone_t * oldzone ;
void * newdata ;
2004-10-03 22:52:02 +00:00
# ifdef NAMEDMALLOCS
if ( ! data )
return Z_MallocNamed ( newsize , file , lineno ) ;
2004-12-02 06:00:21 +00:00
oldzone = ( ( zone_t * ) ( ( char * ) data - ZONEDEBUG ) ) - 1 ;
2004-11-23 00:31:46 +00:00
if ( oldzone - > size = = newsize )
return data ;
2004-10-03 22:52:02 +00:00
newdata = Z_MallocNamed ( newsize , file , lineno ) ;
# else
2004-08-21 01:25:48 +00:00
if ( ! data )
2004-09-20 23:25:38 +00:00
return Z_Malloc ( newsize ) ;
2004-12-02 06:00:21 +00:00
oldzone = ( ( zone_t * ) ( ( char * ) data - ZONEDEBUG ) ) - 1 ;
2004-11-23 00:31:46 +00:00
if ( oldzone - > size = = newsize )
return data ;
2004-08-21 01:25:48 +00:00
newdata = BZ_Malloc ( newsize ) ;
2004-10-03 22:52:02 +00:00
# endif
2004-08-21 01:25:48 +00:00
if ( oldzone - > size < newsize )
{
memcpy ( newdata , data , oldzone - > size ) ;
memset ( ( char * ) newdata + oldzone - > size , 0 , newsize - oldzone - > size ) ;
}
else
memcpy ( newdata , data , newsize ) ;
BZ_Free ( data ) ;
return newdata ;
}
void BZ_Free ( void * data )
{
Z_Free ( data ) ;
}
2005-09-21 01:14:04 +00:00
# ifdef NAMEDMALLOCS
// Zone_Groups_f: prints out zones sorting into groups
// and tracking number of allocs and total group size as
// well as a group delta against the last Zone_Group_f call
# define ZONEGROUPS 64
void Zone_Groups_f ( void )
{
zone_t * zone ;
char * zonename [ ZONEGROUPS ] ;
int zonesize [ ZONEGROUPS ] ;
int zoneallocs [ ZONEGROUPS ] ;
static int zonelast [ ZONEGROUPS ] ;
int groups , i ;
int allocated = 0 ;
// initialization
for ( groups = 0 ; groups < ZONEGROUPS ; groups + + )
zonename [ groups ] = NULL ;
groups = 0 ;
i = 0 ;
for ( zone = zone_head ; zone ; zone = zone - > next )
{
char * czg = ( char * ) ( zone + 1 ) + zone - > size + ZONEDEBUG * 2 ;
// check against existing tracked groups
for ( i = 0 ; i < groups ; i + + )
{
if ( ! strcmp ( czg , zonename [ i ] ) )
{
// update stats for tracked group
zonesize [ i ] + = zone - > size ;
zoneallocs [ i ] + + ;
break ;
}
}
if ( groups = = i ) // no existing group found
{
// track new zone group
zonename [ groups ] = czg ;
zonesize [ groups ] = zone - > size ;
zoneallocs [ groups ] = 1 ;
groups + + ;
// max groups bounds check
if ( groups > = ZONEGROUPS )
{
groups = ZONEGROUPS ;
break ;
}
}
}
// print group statistics
for ( i = 0 ; i < groups ; i + + )
{
allocated + = zonesize [ i ] ;
Con_Printf ( " %s, size: %i, allocs: %i, delta: %i \n " , zonename [ i ] , zonesize [ i ] , zoneallocs [ i ] , zonesize [ i ] - zonelast [ i ] ) ;
zonelast [ i ] = zonesize [ i ] ; // update delta tracking for next call
}
Con_Printf ( " Total: %i bytes \n " , allocated ) ;
}
# endif
2004-08-21 01:25:48 +00:00
void Zone_Print_f ( void )
{
int overhead = 0 ;
int allocated = 0 ;
int blocks = 0 ;
2004-10-01 22:16:44 +00:00
int futurehide = false ;
2004-10-03 22:52:02 +00:00
int minsize = 0 ;
2004-08-21 01:25:48 +00:00
zone_t * zone ;
2004-12-02 06:00:21 +00:00
# if ZONEDEBUG > 0
2004-12-05 11:36:34 +00:00
# ifdef NAMEDMALLOCS
2004-10-10 06:32:29 +00:00
int i ;
qbyte * sent ;
2004-12-05 11:36:34 +00:00
# endif
2004-10-01 22:16:44 +00:00
qboolean testsent = false ;
if ( * Cmd_Argv ( 1 ) = = ' t ' )
{
Con_Printf ( " Testing Zone sentinels \n " ) ;
testsent = true ;
}
2004-08-21 01:25:48 +00:00
else
2004-10-01 22:16:44 +00:00
# endif
2005-09-21 01:14:04 +00:00
if ( * Cmd_Argv ( 1 ) = = ' h ' )
2004-10-01 22:16:44 +00:00
futurehide = true ;
2004-10-03 22:52:02 +00:00
else if ( * Cmd_Argv ( 1 ) )
minsize = atoi ( Cmd_Argv ( 1 ) ) ;
2004-08-21 01:25:48 +00:00
for ( zone = zone_head ; zone ; zone = zone - > next )
{
blocks + + ;
allocated + = zone - > size ;
2004-10-01 22:16:44 +00:00
2004-08-21 01:25:48 +00:00
# ifdef NAMEDMALLOCS
2004-12-02 06:00:21 +00:00
if ( * ( ( char * ) ( zone + 1 ) + zone - > size + ZONEDEBUG * 2 ) ! = ' # ' )
2004-08-21 01:25:48 +00:00
{
2004-12-02 06:00:21 +00:00
# if ZONEDEBUG > 0
2004-10-01 22:16:44 +00:00
if ( testsent )
{
sent = ( qbyte * ) ( zone + 1 ) ;
2004-12-02 06:00:21 +00:00
for ( i = 0 ; i < ZONEDEBUG ; i + + )
2004-10-01 22:16:44 +00:00
{
if ( sent [ i ] ! = sentinalkey )
{
2007-09-23 15:28:06 +00:00
Con_Printf ( CON_ERROR " %i %i-%s \n " , zone - > size , i , ( char * ) ( zone + 1 ) + zone - > size + ZONEDEBUG * 2 ) ;
2004-10-01 22:16:44 +00:00
break ;
}
}
2004-12-02 06:00:21 +00:00
sent + = zone - > size + ZONEDEBUG ;
for ( i = 0 ; i < ZONEDEBUG ; i + + )
2004-10-01 22:16:44 +00:00
{
if ( sent [ i ] ! = sentinalkey )
{
2007-09-23 15:28:06 +00:00
Con_Printf ( CON_ERROR " %i %i-%s \n " , zone - > size , i , ( char * ) ( zone + 1 ) + zone - > size + ZONEDEBUG * 2 ) ;
2004-10-01 22:16:44 +00:00
break ;
}
}
}
2004-10-03 22:52:02 +00:00
else if ( zone - > size > = minsize )
2004-10-01 22:16:44 +00:00
# endif
2004-12-02 06:00:21 +00:00
Con_Printf ( " %i-%s \n " , zone - > size , ( char * ) ( zone + 1 ) + zone - > size + ZONEDEBUG * 2 ) ;
2004-08-21 01:25:48 +00:00
if ( futurehide )
2004-12-02 06:00:21 +00:00
* ( ( char * ) ( zone + 1 ) + zone - > size + ZONEDEBUG * 2 ) = ' # ' ;
2004-08-21 01:25:48 +00:00
// Sleep(10);
}
2004-12-02 06:00:21 +00:00
overhead + = sizeof ( zone_t ) + ZONEDEBUG * 2 + strlen ( ( char * ) ( zone + 1 ) + zone - > size + ZONEDEBUG * 2 ) + 1 ;
2004-08-21 01:25:48 +00:00
# else
Con_Printf ( " %i-%i " , zone - > size , zone - > tag ) ;
2004-12-02 06:00:21 +00:00
overhead + = sizeof ( zone_t ) + ZONEDEBUG * 2 ;
2004-08-21 01:25:48 +00:00
# endif
}
2007-09-23 15:28:06 +00:00
Con_Printf ( CON_NOTICE " Zone:%i bytes in %i blocks \n " , allocated , blocks ) ;
Con_Printf ( CON_NOTICE " Overhead %i bytes \n " , overhead ) ;
2004-08-21 01:25:48 +00:00
}
2008-05-09 14:22:37 +00:00
# elif 0 //#else
2004-08-21 01:25:48 +00:00
//dmw was 0x50000 19/12/02 - playing with dynamic sound system.
//was 0x80000 15/01/03 - playing with genuine pk3 files
# define DYNAMIC_SIZE 0x100000
# 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 ;
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
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 * ) ( ( qbyte * ) 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 * ) ( ( qbyte * ) 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
= = = = = = = = = = = = = = = = = = = = = = = =
*/
# undef 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_MallocNamed ( int size , char * name )
{
void * buf ;
Z_CheckHeap ( ) ; // DEBUG
buf = Z_TagMalloc ( size , 1 ) ;
if ( ! buf )
Sys_Error ( " Z_Malloc: %s failed on allocation of %i bytes " , name , size ) ;
// Sys_DebugLog("zmalloc.log", "%s allocates %i bytes\n", name, size);
Q_memset ( buf , 0 , size ) ;
return buf ;
}
void * Z_MallocNamed2 ( int size , char * name , int line )
{
void * buf ;
Z_CheckHeap ( ) ; // DEBUG
buf = Z_TagMalloc ( size , 1 ) ;
if ( ! buf )
Sys_Error ( " Z_Malloc: %s %i failed on allocation of %i bytes " , name , line , size ) ;
// Sys_DebugLog("zmalloc.log", "%s %i allocates %i bytes\n", name, line, size);
Q_memset ( buf , 0 , size ) ;
return buf ;
}
void * Z_TagMalloc ( int size , int tag )
{
int extra ;
2006-06-02 17:42:36 +00:00
memblock_t * start , * rover , * newz , * base ;
2004-08-21 01:25:48 +00:00
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-qbyte 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
2006-06-02 17:42:36 +00:00
newz = ( memblock_t * ) ( ( qbyte * ) base + size ) ;
newz - > size = extra ;
newz - > tag = 0 ; // free block
newz - > prev = base ;
newz - > id = ZONEID ;
newz - > next = base - > next ;
newz - > next - > prev = newz ;
base - > next = newz ;
2004-08-21 01:25:48 +00:00
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 * ) ( ( qbyte * ) base + base - > size - 4 ) = ZONEID ;
return ( void * ) ( ( qbyte * ) 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 ( ( qbyte * ) block + block - > size ! = ( qbyte * ) 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 " ) ;
}
}
void * BZ_Malloc ( int size )
{
void * data ;
data = malloc ( size ) ;
memset ( data , 0 , size ) ;
return data ;
}
void BZ_Free ( void * data )
{
free ( data ) ;
}
# endif
//============================================================================
# define HUNK_SENTINAL 0x1df001ed
typedef struct
{
int sentinal ;
int size ; // including sizeof(hunk_t), -1 = not allocated
char name [ 8 ] ;
} hunk_t ;
qbyte * 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 ; ( qbyte * ) h ! = hunk_base + hunk_low_used ; )
{
if ( h - > sentinal ! = HUNK_SENTINAL )
Sys_Error ( " Hunk_Check: trahsed sentinal " ) ;
2004-12-02 06:00:21 +00:00
if ( h - > size < 16 + HUNKDEBUG * 2 | | h - > size + ( qbyte * ) h - hunk_base > hunk_size )
2004-08-21 01:25:48 +00:00
Sys_Error ( " Hunk_Check: bad size " ) ;
2004-12-02 06:00:21 +00:00
# if HUNKDEBUG > 0
2004-10-10 06:32:29 +00:00
{
qbyte * present ;
qbyte * postsent ;
int i ;
present = ( qbyte * ) ( h + 1 ) ;
2004-12-02 06:00:21 +00:00
postsent = ( qbyte * ) h + h - > size - HUNKDEBUG ;
for ( i = 0 ; i < HUNKDEBUG ; i + + )
2004-10-10 06:32:29 +00:00
{
if ( present [ i ] ! = sentinalkey )
* ( int * ) 0 = - 3 ;
if ( postsent [ i ] ! = sentinalkey )
* ( int * ) 0 = - 3 ;
}
}
# endif
2004-08-21 01:25:48 +00:00
h = ( hunk_t * ) ( ( qbyte * ) 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 ;
2012-05-09 15:30:53 +00:00
2004-08-21 01:25:48 +00:00
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 ) ;
2012-05-09 15:30:53 +00:00
Con_Printf ( " :%12i total hunk size \n " , hunk_size ) ;
2004-08-21 01:25:48 +00:00
Con_Printf ( " ------------------------- \n " ) ;
while ( 1 )
{
//
// skip to the high hunk if done with low hunk
//
if ( h = = endlow )
{
Con_Printf ( " ------------------------- \n " ) ;
2012-05-09 15:30:53 +00:00
Con_Printf ( " : %12i REMAINING \n " , hunk_size - hunk_low_used - hunk_high_used ) ;
Con_Printf ( " : %12i USED \n " , hunk_low_used + hunk_high_used ) ;
2004-08-21 01:25:48 +00:00
Con_Printf ( " ------------------------- \n " ) ;
h = starthigh ;
}
2012-05-09 15:30:53 +00:00
2004-08-21 01:25:48 +00:00
//
// 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 + ( qbyte * ) h - hunk_base > hunk_size )
Sys_Error ( " Hunk_Check: bad size " ) ;
2004-12-02 06:00:21 +00:00
# if HUNKDEBUG > 0
2004-10-10 06:32:29 +00:00
{
qbyte * present ;
qbyte * postsent ;
int i ;
present = ( qbyte * ) ( h + 1 ) ;
2004-12-02 06:00:21 +00:00
postsent = ( qbyte * ) h + h - > size - HUNKDEBUG ;
for ( i = 0 ; i < HUNKDEBUG ; i + + )
2004-10-10 06:32:29 +00:00
{
if ( present [ i ] ! = sentinalkey )
* ( int * ) 0 = - 3 ;
if ( postsent [ i ] ! = sentinalkey )
* ( int * ) 0 = - 3 ;
}
}
# endif
2004-08-21 01:25:48 +00:00
next = ( hunk_t * ) ( ( qbyte * ) h + h - > size ) ;
count + + ;
totalblocks + + ;
sum + = h - > size ;
//
// print the single block
//
memcpy ( name , h - > name , 8 ) ;
if ( all )
2012-05-09 15:30:53 +00:00
Con_Printf ( " %8p :%12i %8s \n " , h , h - > size , name ) ;
2004-08-21 01:25:48 +00:00
//
// print the total
//
if ( next = = endlow | | next = = endhigh | |
strncmp ( h - > name , next - > name , 8 ) )
{
if ( ! all )
2012-05-09 15:30:53 +00:00
Con_Printf ( " :%12i %8s (TOTAL) \n " , sum , name ) ;
2004-08-21 01:25:48 +00:00
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 )
{
2005-06-14 04:52:10 +00:00
# ifdef NOHIGH
int roundup ;
2005-10-16 15:22:27 +00:00
int roundupold ;
2005-06-14 04:52:10 +00:00
# endif
2004-08-21 01:25:48 +00:00
hunk_t * h ;
# ifdef PARANOID
Hunk_Check ( ) ;
# endif
if ( size < 0 )
Sys_Error ( " Hunk_Alloc: bad size: %i " , size ) ;
2004-12-02 06:00:21 +00:00
size = sizeof ( hunk_t ) + HUNKDEBUG * 2 + ( ( size + 15 ) & ~ 15 ) ;
2004-08-21 01:25:48 +00:00
# ifndef _WIN32
if ( hunk_size - hunk_low_used - hunk_high_used < size )
// Sys_Error ("Hunk_Alloc: failed on %i bytes",size);
# ifdef _WIN32
Sys_Error ( " Not enough RAM allocated on allocation of \" %s \" . Try starting using \" -heapsize 16000 \" on the QuakeWorld command line. " , name ) ;
# else
Android: fat presses, vibrator, onscreen keyboard, keep-screen-on, console scaling, touch-based console scrolling, additional bindables.
Some memory leaks fixed.
latency with the nq protocol over loopback is much reduced.
Terrain: now mostly a property of a (q1 for now) bsp map, file format changed, glsl now built in, terrain editor builtin improved/changed, holes supported.
git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4067 fc73d0e0-1445-4013-8a0c-d673dee63da5
2012-07-14 16:25:18 +00:00
Sys_Error ( " Not enough RAM allocated. Try starting using \" -mem %u \" on the QuakeWorld command line. " , ( hunk_size + 8 * 1024 * 1024 ) / 1024 * 1024 ) ;
2004-08-21 01:25:48 +00:00
# endif
# endif
2004-10-10 06:32:29 +00:00
2004-08-21 01:25:48 +00:00
h = ( hunk_t * ) ( hunk_base + hunk_low_used ) ;
2004-12-02 06:00:21 +00:00
# ifdef NOHIGH
2005-10-16 15:22:27 +00:00
roundupold = hunk_low_used + sizeof ( hunk_t ) ;
roundupold + = 1024 * 128 ;
roundupold & = ~ ( 1024 * 128 - 1 ) ;
2005-06-14 04:52:10 +00:00
roundup = hunk_low_used + size + sizeof ( hunk_t ) ;
2005-10-16 15:22:27 +00:00
roundup + = 1024 * 128 ;
roundup & = ~ ( 1024 * 128 - 1 ) ;
2005-10-18 04:38:22 +00:00
if ( ! hunk_low_used | | roundup ! = roundupold )
2005-06-14 04:52:10 +00:00
if ( ! VirtualAlloc ( hunk_base , roundup , MEM_COMMIT , PAGE_READWRITE ) )
2004-08-21 01:25:48 +00:00
{
char * buf ;
Hunk_Print ( true ) ;
FormatMessage ( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM , NULL , GetLastError ( ) , MAKELANGID ( LANG_NEUTRAL , SUBLANG_DEFAULT ) , ( LPTSTR ) & buf , 0 , NULL ) ;
2010-03-14 14:35:56 +00:00
Sys_Error ( " VirtualCommit failed \n Not enough RAM allocated on allocation of \" %s \" . Try starting using \" -heapsize %i \" on the QuakeWorld command line. " , name , roundupold / 512 ) ;
2004-08-21 01:25:48 +00:00
}
# endif
hunk_low_used + = size ;
Cache_FreeLow ( hunk_low_used ) ;
2004-12-02 06:00:21 +00:00
memset ( h , 0 , size - HUNKDEBUG ) ;
2004-10-10 06:32:29 +00:00
2004-12-02 06:00:21 +00:00
# if HUNKDEBUG>0
memset ( ( h + 1 ) , sentinalkey , HUNKDEBUG ) ;
memset ( ( qbyte * ) h + size - HUNKDEBUG , sentinalkey , HUNKDEBUG ) ;
2004-10-10 06:32:29 +00:00
# endif
2004-08-21 01:25:48 +00:00
h - > size = size ;
h - > sentinal = HUNK_SENTINAL ;
Q_strncpyz ( h - > name , COM_SkipPath ( name ) , sizeof ( h - > name ) ) ;
2004-12-02 06:00:21 +00:00
return ( void * ) ( ( char * ) ( h + 1 ) + HUNKDEBUG ) ;
2004-08-21 01:25:48 +00:00
}
/*
= = = = = = = = = = = = = = = = = = =
Hunk_Alloc
= = = = = = = = = = = = = = = = = = =
*/
void * Hunk_Alloc ( int size )
{
return Hunk_AllocName ( size , " unknown " ) ;
}
int Hunk_LowMark ( void )
{
return hunk_low_used ;
}
int Hunk_LowMemAvailable ( void )
{
return hunk_size - hunk_low_used - hunk_high_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 ;
2004-12-02 06:00:21 +00:00
# ifdef NOHIGH
2004-08-21 01:25:48 +00:00
if ( ! VirtualAlloc ( hunk_base , hunk_low_used + sizeof ( hunk_t ) , MEM_COMMIT , PAGE_READWRITE ) )
{
char * buf ;
FormatMessage ( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM , NULL , GetLastError ( ) , MAKELANGID ( LANG_NEUTRAL , SUBLANG_DEFAULT ) , ( LPTSTR ) & buf , 0 , NULL ) ;
Sys_Error ( " VirtualAlloc commit failed. \n %s " , buf ) ;
}
# endif
}
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 )
{
2004-12-02 06:00:21 +00:00
# ifdef NOHIGH
2004-08-21 01:25:48 +00:00
Sys_Error ( " High hunk was disabled " ) ;
2004-09-20 23:25:38 +00:00
return NULL ;
# else
hunk_t * h ;
2004-08-21 01:25:48 +00:00
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_strncpyz ( h - > name , name , sizeof ( h - > name ) ) ;
return ( void * ) ( h + 1 ) ;
2004-09-20 23:25:38 +00:00
# endif
2004-08-21 01:25:48 +00:00
}
/*
= = = = = = = = = = = = = = = = =
Hunk_TempAlloc
Return space from the top of the hunk
clears old temp .
= = = = = = = = = = = = = = = = =
*/
2004-12-02 06:00:21 +00:00
# ifdef NOHIGH
2004-08-21 01:25:48 +00:00
typedef struct hnktemps_s {
struct hnktemps_s * next ;
2004-12-02 06:00:21 +00:00
# if TEMPDEBUG>0
2004-09-20 23:25:38 +00:00
int len ;
# endif
2004-08-21 01:25:48 +00:00
} hnktemps_t ;
hnktemps_t * hnktemps ;
void Hunk_TempFree ( void )
{
hnktemps_t * nt ;
while ( hnktemps )
{
2004-12-02 06:00:21 +00:00
# if TEMPDEBUG>0
2004-09-20 23:25:38 +00:00
int i ;
qbyte * buf ;
buf = ( qbyte * ) ( hnktemps + 1 ) ;
2004-12-02 06:00:21 +00:00
for ( i = 0 ; i < TEMPDEBUG ; i + + )
2004-09-20 23:25:38 +00:00
{
if ( buf [ i ] ! = sentinalkey )
* ( int * ) 0 = - 3 ; //force a crash... this'll get our attention.
}
2004-12-02 06:00:21 +00:00
buf + = TEMPDEBUG ;
2004-09-20 23:25:38 +00:00
//app data
buf + = hnktemps - > len ;
2004-12-02 06:00:21 +00:00
for ( i = 0 ; i < TEMPDEBUG ; i + + )
2004-09-20 23:25:38 +00:00
{
if ( buf [ i ] ! = sentinalkey )
* ( int * ) 0 = - 3 ; //force a crash... this'll get our attention.
}
# endif
2004-08-21 01:25:48 +00:00
nt = hnktemps - > next ;
2004-09-20 23:25:38 +00:00
2004-08-21 01:25:48 +00:00
free ( hnktemps ) ;
hnktemps = nt ;
}
}
# endif
//allocates without clearing previous temp.
//safer than my hack that fuh moaned about...
void * Hunk_TempAllocMore ( int size )
{
void * buf ;
2004-12-02 06:00:21 +00:00
# ifdef NOHIGH
# if TEMPDEBUG>0
2004-09-20 23:25:38 +00:00
hnktemps_t * nt ;
2005-03-28 00:11:59 +00:00
nt = ( hnktemps_t * ) malloc ( size + sizeof ( hnktemps_t ) + TEMPDEBUG * 2 ) ;
2012-02-12 05:18:31 +00:00
if ( ! nt )
return NULL ;
2004-09-20 23:25:38 +00:00
nt - > next = hnktemps ;
nt - > len = size ;
hnktemps = nt ;
buf = ( void * ) ( nt + 1 ) ;
2004-12-02 06:00:21 +00:00
memset ( buf , sentinalkey , TEMPDEBUG ) ;
buf = ( char * ) buf + TEMPDEBUG ;
2004-09-20 23:25:38 +00:00
memset ( buf , 0 , size ) ;
2004-12-02 06:00:21 +00:00
memset ( ( char * ) buf + size , sentinalkey , TEMPDEBUG ) ;
2004-09-20 23:25:38 +00:00
return buf ;
# else
2004-08-21 01:25:48 +00:00
hnktemps_t * nt ;
2005-03-28 00:11:59 +00:00
nt = ( hnktemps_t * ) malloc ( size + sizeof ( hnktemps_t ) ) ;
2012-02-12 05:18:31 +00:00
if ( ! nt )
return NULL ;
2004-08-21 01:25:48 +00:00
nt - > next = hnktemps ;
hnktemps = nt ;
buf = ( void * ) ( nt + 1 ) ;
memset ( buf , 0 , size ) ;
return buf ;
2004-09-20 23:25:38 +00:00
# endif
2004-08-21 01:25:48 +00:00
# else
if ( ! hunk_tempactive )
return Hunk_TempAlloc ( size ) ;
size = ( size + 15 ) & ~ 15 ;
hunk_tempactive = false ; //so it doesn't wipe old temp.
buf = Hunk_HighAllocName ( size , " mtmp " ) ;
hunk_tempactive = true ;
return buf ;
# endif
}
void * Hunk_TempAlloc ( int size )
{
2004-12-02 06:00:21 +00:00
# ifdef NOHIGH
2004-08-21 01:25:48 +00:00
Hunk_TempFree ( ) ;
return Hunk_TempAllocMore ( size ) ;
# else
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 ;
# endif
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
CACHE MEMORY
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
# ifdef NOCACHE
typedef struct cache_system_s {
cache_user_t * user ;
struct cache_system_s * next ;
struct cache_system_s * prev ;
int size ;
char name [ 16 ] ;
} cache_system_t ;
cache_system_t * cache_head ;
void Cache_Free ( cache_user_t * c )
{
cache_system_t * cs ;
2006-02-22 23:46:22 +00:00
if ( c - > data = = NULL )
{
cache_head = NULL ; //this is evil and should never happen
2006-02-23 00:16:18 +00:00
Sys_Error ( " Cache was already free \n " ) ;
2006-02-22 23:46:22 +00:00
return ;
}
2004-08-21 01:25:48 +00:00
cs = ( ( cache_system_t * ) c - > data ) - 1 ;
2004-12-02 06:00:21 +00:00
cs = ( cache_system_t * ) ( ( char * ) cs - CACHEDEBUG ) ;
2004-08-21 01:25:48 +00:00
cs - > user - > data = NULL ;
2004-12-02 06:00:21 +00:00
# if CACHEDEBUG>0
{
int i ;
qbyte * buf ;
buf = ( qbyte * ) ( cs + 1 ) ;
for ( i = 0 ; i < CACHEDEBUG ; i + + )
{
if ( buf [ i ] ! = sentinalkey )
2006-01-02 22:57:18 +00:00
Sys_Error ( " Cache memory corrupted (%i? bytes) " , cs - > size ) ;
2004-12-02 06:00:21 +00:00
}
buf + = CACHEDEBUG ;
//app data
buf + = cs - > size ;
for ( i = 0 ; i < CACHEDEBUG ; i + + )
{
if ( buf [ i ] ! = sentinalkey )
2006-01-02 22:57:18 +00:00
Sys_Error ( " Cache memory corrupted (%i? bytes) " , cs - > size ) ;
2004-12-02 06:00:21 +00:00
}
}
# endif
2004-08-21 01:25:48 +00:00
if ( cs - > next )
cs - > next - > prev = cs - > prev ;
if ( cs - > prev )
cs - > prev - > next = cs - > next ;
if ( cs = = cache_head )
cache_head = cs - > next ;
2006-01-02 22:57:18 +00:00
BZ_Free ( cs ) ;
2004-08-21 01:25:48 +00:00
}
void * Cache_Check ( cache_user_t * c )
{
if ( ! c - > data )
return NULL ;
return c - > data ;
}
void Cache_Flush ( void )
{
2012-02-27 13:55:23 +00:00
# ifndef SERVERONLY
2012-02-27 12:23:15 +00:00
S_Purge ( false ) ;
2012-02-27 13:55:23 +00:00
# endif
2004-08-21 01:25:48 +00:00
while ( cache_head )
{
Cache_Free ( cache_head - > user ) ;
}
}
void * Cache_Alloc ( cache_user_t * c , int size , char * name )
{
void * buf ;
cache_system_t * nt ;
if ( c - > data )
2005-07-28 15:22:15 +00:00
Sys_Error ( " Cache_Alloc: already allocated " ) ;
2009-11-17 00:15:44 +00:00
2004-08-21 01:25:48 +00:00
if ( size < = 0 )
Sys_Error ( " Cache_Alloc: size %i " , size ) ;
2004-12-02 06:00:21 +00:00
// size = (size + 15) & ~15;
2004-08-21 01:25:48 +00:00
2006-01-02 22:57:18 +00:00
nt = ( cache_system_t * ) BZ_Malloc ( size + sizeof ( cache_system_t ) + CACHEDEBUG * 2 ) ;
2004-08-21 01:25:48 +00:00
if ( ! nt )
Sys_Error ( " Cache_Alloc: failed on allocation of %i bytes " , size ) ;
nt - > next = cache_head ;
nt - > prev = NULL ;
nt - > user = c ;
2004-12-02 06:00:21 +00:00
nt - > size = size ;
2004-08-21 01:25:48 +00:00
Q_strncpyz ( nt - > name , name , sizeof ( nt - > name ) ) ;
if ( cache_head )
cache_head - > prev = nt ;
cache_head = nt ;
nt - > user - > fake = false ;
buf = ( void * ) ( nt + 1 ) ;
2004-12-02 06:00:21 +00:00
memset ( buf , sentinalkey , CACHEDEBUG ) ;
buf = ( char * ) buf + CACHEDEBUG ;
2004-08-21 01:25:48 +00:00
memset ( buf , 0 , size ) ;
2004-12-02 06:00:21 +00:00
memset ( ( char * ) buf + size , sentinalkey , CACHEDEBUG ) ;
2004-08-21 01:25:48 +00:00
c - > data = buf ;
return c - > data ;
}
void Cache_FreeLow ( int newlow )
{
}
void Cache_FreeHigh ( int newhigh )
{
}
void Cache_Report ( void )
{
}
void Hunk_Print_f ( void )
{
cache_system_t * cs ;
int zoneblocks ;
int cacheused ;
int zoneused ;
Hunk_Print ( true ) ;
cacheused = 0 ;
zoneused = 0 ;
zoneblocks = 0 ;
for ( cs = cache_head ; cs ; cs = cs - > next )
{
cacheused + = cs - > size ;
}
2008-05-09 14:22:37 +00:00
Con_Printf ( " Cache: %iKB \n " , cacheused / 1024 ) ;
2012-05-09 15:30:53 +00:00
Con_Printf ( " Z Delta: %iKB \n " , zmemdelta / 1024 ) ; zmemdelta = 0 ;
Con_Printf ( " Z Total: %iKB \n " , zmemtotal / 1024 ) ;
//note: Zone memory isn't tracked reliably. we don't track the mem that is freed, so it'll just climb and climb
//we don't track reallocs either.
2008-05-09 14:22:37 +00:00
#if 0
2004-08-21 01:25:48 +00:00
{
2008-05-09 14:22:37 +00:00
zone_t * zone ;
for ( zone = zone_head ; zone ; zone = zone - > next )
{
zoneused + = zone - > size + sizeof ( zone_t ) ;
zoneblocks + + ;
}
Con_Printf ( " Zone: %i containing %iKB \n " , zoneblocks , zoneused / 1024 ) ;
2004-08-21 01:25:48 +00:00
}
2008-05-09 14:22:37 +00:00
# endif
2012-07-05 19:42:36 +00:00
# ifdef USE_MSVCRT_DEBUG
{
static struct _CrtMemState savedstate ;
static qboolean statesaved ;
_CrtMemDumpAllObjectsSince ( statesaved ? & savedstate : NULL ) ;
_CrtMemCheckpoint ( & savedstate ) ;
statesaved = true ;
}
# endif
2004-08-21 01:25:48 +00:00
}
void Cache_Init ( void )
{
Cmd_AddCommand ( " flush " , Cache_Flush ) ;
Cmd_AddCommand ( " hunkprint " , Hunk_Print_f ) ;
2008-05-09 14:22:37 +00:00
#if 0
2004-08-21 01:25:48 +00:00
Cmd_AddCommand ( " zoneprint " , Zone_Print_f ) ;
2008-05-09 14:22:37 +00:00
# endif
2005-09-21 01:14:04 +00:00
# ifdef NAMEDMALLOCS
Cmd_AddCommand ( " zonegroups " , Zone_Groups_f ) ;
# endif
2004-08-21 01:25:48 +00:00
}
# else
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 )
{
2006-06-02 17:42:36 +00:00
cache_system_t * newc ;
2004-08-21 01:25:48 +00:00
// we are clearing up space at the bottom, so only allocate it late
2006-06-02 17:42:36 +00:00
newc = Cache_TryAlloc ( c - > size , true ) ;
if ( newc )
2004-08-21 01:25:48 +00:00
{
// Con_Printf ("cache_move ok\n");
2006-06-02 17:42:36 +00:00
Q_memcpy ( newc + 1 , c + 1 , c - > size - sizeof ( cache_system_t ) ) ;
newc - > user = c - > user ;
Q_memcpy ( newc - > name , c - > name , sizeof ( newc - > name ) ) ;
2004-08-21 01:25:48 +00:00
Cache_Free ( c - > user ) ;
2006-06-02 17:42:36 +00:00
newc - > user - > data = ( void * ) ( newc + 1 ) ;
2004-08-21 01:25:48 +00:00
}
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 ( ( qbyte * ) 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 ( ( qbyte * ) 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 )
{
2006-06-02 17:42:36 +00:00
cache_system_t * cs , * newc ;
2004-08-21 01:25:48 +00:00
// 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 ) ;
2006-06-02 17:42:36 +00:00
newc = ( cache_system_t * ) ( hunk_base + hunk_low_used ) ;
memset ( newc , 0 , sizeof ( * newc ) ) ;
newc - > size = size ;
2004-08-21 01:25:48 +00:00
2006-06-02 17:42:36 +00:00
cache_head . prev = cache_head . next = newc ;
newc - > prev = newc - > next = & cache_head ;
2004-08-21 01:25:48 +00:00
2006-06-02 17:42:36 +00:00
Cache_MakeLRU ( newc ) ;
return newc ;
2004-08-21 01:25:48 +00:00
}
// search from the bottom up for space
2006-06-02 17:42:36 +00:00
newc = ( cache_system_t * ) ( hunk_base + hunk_low_used ) ;
2004-08-21 01:25:48 +00:00
cs = cache_head . next ;
do
{
if ( ! nobottom | | cs ! = cache_head . next )
{
2006-06-02 17:42:36 +00:00
if ( ( qbyte * ) cs - ( qbyte * ) newc > = size )
2004-08-21 01:25:48 +00:00
{ // found space
2006-06-02 17:42:36 +00:00
memset ( newc , 0 , sizeof ( * newc ) ) ;
newc - > size = size ;
2004-08-21 01:25:48 +00:00
2006-06-02 17:42:36 +00:00
newc - > next = cs ;
newc - > prev = cs - > prev ;
cs - > prev - > next = newc ;
cs - > prev = newc ;
2004-08-21 01:25:48 +00:00
2006-06-02 17:42:36 +00:00
Cache_MakeLRU ( newc ) ;
2004-08-21 01:25:48 +00:00
2006-06-02 17:42:36 +00:00
return newc ;
2004-08-21 01:25:48 +00:00
}
}
// continue looking
2006-06-02 17:42:36 +00:00
newc = ( cache_system_t * ) ( ( qbyte * ) cs + cs - > size ) ;
2004-08-21 01:25:48 +00:00
cs = cs - > next ;
} while ( cs ! = & cache_head ) ;
// try to allocate one at the very end
2006-06-02 17:42:36 +00:00
if ( hunk_base + hunk_size - hunk_high_used - ( qbyte * ) newc > = size )
2004-08-21 01:25:48 +00:00
{
2006-06-02 17:42:36 +00:00
memset ( newc , 0 , sizeof ( * newc ) ) ;
newc - > size = size ;
2004-08-21 01:25:48 +00:00
2006-06-02 17:42:36 +00:00
newc - > next = & cache_head ;
newc - > prev = cache_head . prev ;
cache_head . prev - > next = newc ;
cache_head . prev = newc ;
2004-08-21 01:25:48 +00:00
2006-06-02 17:42:36 +00:00
Cache_MakeLRU ( newc ) ;
2004-08-21 01:25:48 +00:00
2006-06-02 17:42:36 +00:00
return newc ;
2004-08-21 01:25:48 +00:00
}
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 Hunk_Print_f ( void ) { Hunk_Print ( true ) ; }
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 ) ;
Cmd_AddCommand ( " hp " , Hunk_Print_f ) ;
}
/*
= = = = = = = = = = = = = =
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 ;
if ( c - > fake ) //malloc or somesuch.
return c - > data ;
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 )
2005-07-28 15:22:15 +00:00
Sys_Error ( " Cache_Alloc: already allocated " ) ;
2004-08-21 01:25:48 +00:00
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 ) ;
}
# endif
//============================================================================
/*
= = = = = = = = = = = = = = = = = = = = = = = =
Memory_Init
= = = = = = = = = = = = = = = = = = = = = = = =
*/
void Memory_Init ( void * buf , int size )
{
2008-05-09 14:22:37 +00:00
#if 0 //ndef NOZONE
2004-08-21 01:25:48 +00:00
int p ;
int zonesize = DYNAMIC_SIZE ;
# endif
2005-03-28 00:11:59 +00:00
hunk_base = ( qbyte * ) buf ;
2004-08-21 01:25:48 +00:00
hunk_size = size ;
hunk_low_used = 0 ;
hunk_high_used = 0 ;
2004-09-20 23:25:38 +00:00
2004-12-02 06:00:21 +00:00
# if ZONEDEBUG>0 || HUNKDEBUG>0 || TEMPDEBUG>0||CACHEDEBUG>0
srand ( time ( 0 ) ) ;
2011-06-29 18:39:11 +00:00
sentinalkey = rand ( ) & 0xff ;
2004-09-20 23:25:38 +00:00
# endif
2004-08-21 01:25:48 +00:00
Cache_Init ( ) ;
2008-05-09 14:22:37 +00:00
# ifdef MULTITHREAD
if ( ! zonelock )
zonelock = Sys_CreateMutex ( ) ; // this can fail!
# endif
#if 0 //ndef NOZONE
2004-08-21 01:25:48 +00:00
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 ) ;
# endif
}
2008-05-09 14:22:37 +00:00
void Memory_DeInit ( void )
{
2009-04-02 22:25:54 +00:00
# ifdef NOHIGH
2009-04-01 22:03:56 +00:00
Hunk_TempFree ( ) ;
2009-04-02 22:25:54 +00:00
# endif
2009-04-01 22:03:56 +00:00
Cache_Flush ( ) ;
2008-05-09 14:22:37 +00:00
# ifdef MULTITHREAD
if ( zonelock )
{
Sys_DestroyMutex ( zonelock ) ;
zonelock = NULL ;
}
# endif
2008-05-14 14:55:25 +00:00
}