2007-11-09 22:00:00 +01:00
//=======================================================================
// Copyright XashXT Group 2007 <20>
// memory.c - zone memory allocation from DarkPlaces
//=======================================================================
2007-11-10 22:00:00 +01:00
# include "launch.h"
2007-11-09 22:00:00 +01:00
# define MEMCLUMPSIZE (65536 - 1536) // give malloc padding so we can't waste most of a page at the end
# define MEMUNIT 8 // smallest unit we care about is this many bytes
# define MEMBITS (MEMCLUMPSIZE / MEMUNIT)
# define MEMBITINTS (MEMBITS / 32)
# define MEMCLUMP_SENTINEL 0xABADCAFE
# define MEMHEADER_SENTINEL1 0xDEADF00D
# define MEMHEADER_SENTINEL2 0xDF
2008-08-28 22:00:00 +02:00
typedef enum
{
PREFETCH_READ , // prefetch assuming that buffer is used for reading only
PREFETCH_WRITE , // prefetch assuming that buffer is used for writing only
PREFETCH_READWRITE // prefetch assuming that buffer is used for both reading and writing
} e_prefetch ;
2007-11-09 22:00:00 +01:00
typedef struct memheader_s
{
struct memheader_s * next ; // next and previous memheaders in chain belonging to pool
struct memheader_s * prev ;
struct mempool_s * pool ; // pool this memheader belongs to
struct memclump_s * clump ; // clump this memheader lives in, NULL if not in a clump
size_t size ; // size of the memory after the header (excluding header and sentinel2)
const char * filename ; // file name and line where Mem_Alloc was called
uint fileline ;
uint sentinel1 ; // should always be MEMHEADER_SENTINEL1
// immediately followed by data, which is followed by a MEMHEADER_SENTINEL2 byte
2007-11-14 22:00:00 +01:00
} memheader_t ;
2007-11-09 22:00:00 +01:00
typedef struct memclump_s
{
byte block [ MEMCLUMPSIZE ] ; // contents of the clump
uint sentinel1 ; // should always be MEMCLUMP_SENTINEL
int bits [ MEMBITINTS ] ; // if a bit is on, it means that the MEMUNIT bytes it represents are allocated, otherwise free
uint sentinel2 ; // should always be MEMCLUMP_SENTINEL
size_t blocksinuse ; // if this drops to 0, the clump is freed
size_t largestavailable ; // largest block of memory available
struct memclump_s * chain ; // next clump in the chain
2007-11-14 22:00:00 +01:00
} memclump_t ;
2007-11-09 22:00:00 +01:00
typedef struct mempool_s
{
uint sentinel1 ; // should always be MEMHEADER_SENTINEL1
struct memheader_s * chain ; // chain of individual memory allocations
struct memclump_s * clumpchain ; // chain of clumps (if any)
size_t totalsize ; // total memory allocated in this pool (inside memheaders)
size_t realsize ; // total memory allocated in this pool (actual malloc total)
size_t lastchecksize ; // updated each time the pool is displayed by memlist
struct mempool_s * next ; // linked into global mempool list
const char * filename ; // file name and line where Mem_AllocPool was called
int fileline ;
char name [ MAX_QPATH ] ; // name of the pool
uint sentinel2 ; // should always be MEMHEADER_SENTINEL1
2007-11-14 22:00:00 +01:00
} mempool_t ;
2007-11-09 22:00:00 +01:00
2008-06-12 22:00:00 +02:00
typedef struct memcluster_s
2007-12-17 22:00:00 +01:00
{
byte * data ;
byte * allocflags ;
size_t numflaggedrecords ;
} memcluster_t ;
2008-06-12 22:00:00 +02:00
typedef struct memarray_s
2007-12-17 22:00:00 +01:00
{
byte * mempool ;
size_t recordsize ;
size_t count ;
size_t numarrays ;
size_t maxarrays ;
memcluster_t * arrays ;
} memarray_t ;
mempool_t * poolchain = NULL ; // critical stuff
2007-11-09 22:00:00 +01:00
2008-08-28 22:00:00 +02:00
void _mem_prefetch ( const void * s , const uint bytes , e_prefetch type )
2007-11-09 22:00:00 +01:00
{
2008-08-28 22:00:00 +02:00
// write buffer prefetching is performed only if
// the processor benefits from it. read and read/write
// prefetching is always performed.
switch ( type )
{
case PREFETCH_WRITE : break ;
case PREFETCH_READ :
case PREFETCH_READWRITE :
__asm
{
mov ebx , s
mov ecx , bytes
cmp ecx , 4096 // clamp to 4kB
jle skipClump
mov ecx , 4096
skipClump :
add ecx , 0x1f
shr ecx , 5 // number of cache lines
jz skip
jmp loopie
align 16
loopie : test byte ptr [ ebx ] , al
add ebx , 32
dec ecx
jnz loopie
skip :
}
break ;
}
}
void _mem_copy ( void * dest , const void * src , size_t count , const char * filename , int fileline )
{
if ( src = = NULL | | count < = 0 ) return ; // nothing to copy
if ( dest = = NULL ) Sys_Error ( " Mem_Copy: dest == NULL (called at %s:%i) \n " , filename , fileline ) ;
2007-11-09 22:00:00 +01:00
// copy block
2008-08-28 22:00:00 +02:00
_mem_prefetch ( src , count , PREFETCH_READ ) ;
__asm
{
push edi
push esi
mov ecx , count
cmp ecx , 0 // count = 0 check (just to be on the safe side)
je outta
mov edx , dest
mov ebx , src
cmp ecx , 32 // padding only?
jl padding
mov edi , ecx
and edi , ~ 31 // edi = count&~31
sub edi , 32
align 16
loopMisAligned :
mov eax , [ ebx + edi + 0 + 0 * 8 ]
mov esi , [ ebx + edi + 4 + 0 * 8 ]
mov [ edx + edi + 0 + 0 * 8 ] , eax
mov [ edx + edi + 4 + 0 * 8 ] , esi
mov eax , [ ebx + edi + 0 + 1 * 8 ]
mov esi , [ ebx + edi + 4 + 1 * 8 ]
mov [ edx + edi + 0 + 1 * 8 ] , eax
mov [ edx + edi + 4 + 1 * 8 ] , esi
mov eax , [ ebx + edi + 0 + 2 * 8 ]
mov esi , [ ebx + edi + 4 + 2 * 8 ]
mov [ edx + edi + 0 + 2 * 8 ] , eax
mov [ edx + edi + 4 + 2 * 8 ] , esi
mov eax , [ ebx + edi + 0 + 3 * 8 ]
mov esi , [ ebx + edi + 4 + 3 * 8 ]
mov [ edx + edi + 0 + 3 * 8 ] , eax
mov [ edx + edi + 4 + 3 * 8 ] , esi
sub edi , 32
jge loopMisAligned
mov edi , ecx
and edi , ~ 31
add ebx , edi // increase src pointer
add edx , edi // increase dst pointer
and ecx , 31 // new count
jz outta // if count = 0, get outta here
padding :
cmp ecx , 16
jl skip16
mov eax , dword ptr [ ebx ]
mov dword ptr [ edx ] , eax
mov eax , dword ptr [ ebx + 4 ]
mov dword ptr [ edx + 4 ] , eax
mov eax , dword ptr [ ebx + 8 ]
mov dword ptr [ edx + 8 ] , eax
mov eax , dword ptr [ ebx + 12 ]
mov dword ptr [ edx + 12 ] , eax
sub ecx , 16
add ebx , 16
add edx , 16
skip16 :
cmp ecx , 8
jl skip8
mov eax , dword ptr [ ebx ]
mov dword ptr [ edx ] , eax
mov eax , dword ptr [ ebx + 4 ]
sub ecx , 8
mov dword ptr [ edx + 4 ] , eax
add ebx , 8
add edx , 8
skip8 :
cmp ecx , 4
jl skip4
mov eax , dword ptr [ ebx ] // here 4-7 bytes
add ebx , 4
sub ecx , 4
mov dword ptr [ edx ] , eax
add edx , 4
skip4 : // 0-3 remaining bytes
cmp ecx , 2
jl skip2
mov ax , word ptr [ ebx ] // two bytes
cmp ecx , 3 // less than 3?
mov word ptr [ edx ] , ax
jl outta
mov al , byte ptr [ ebx + 2 ] // last byte
mov byte ptr [ edx + 2 ] , al
jmp outta
skip2 :
cmp ecx , 1
jl outta
mov al , byte ptr [ ebx ]
mov byte ptr [ edx ] , al
outta :
pop esi
pop edi
}
2007-11-09 22:00:00 +01:00
}
2008-09-10 22:00:00 +02:00
void _mem_set ( void * dest , int set , size_t size , const char * filename , int fileline )
{
2008-10-19 22:00:00 +02:00
// FIXME: implement
Sys_Error ( " _mem_set: not implemented (called at %s:%i) \n " , filename , fileline ) ;
2008-09-10 22:00:00 +02:00
}
2008-08-28 22:00:00 +02:00
void * _mem_alloc ( byte * poolptr , size_t size , const char * filename , int fileline )
2007-11-09 22:00:00 +01:00
{
int i , j , k , needed , endbit , largest ;
memclump_t * clump , * * clumpchainpointer ;
memheader_t * mem ;
mempool_t * pool = ( mempool_t * ) ( ( byte * ) poolptr ) ;
if ( size < = 0 ) return NULL ;
2008-01-07 22:00:00 +01:00
if ( poolptr = = NULL ) Sys_Error ( " Mem_Alloc: pool == NULL (alloc at %s:%i) \n " , filename , fileline ) ;
2007-11-09 22:00:00 +01:00
pool - > totalsize + = size ;
if ( size < 4096 )
{
// clumping
needed = ( sizeof ( memheader_t ) + size + sizeof ( int ) + ( MEMUNIT - 1 ) ) / MEMUNIT ;
endbit = MEMBITS - needed ;
for ( clumpchainpointer = & pool - > clumpchain ; * clumpchainpointer ; clumpchainpointer = & ( * clumpchainpointer ) - > chain )
{
clump = * clumpchainpointer ;
if ( clump - > sentinel1 ! = MEMCLUMP_SENTINEL )
2008-01-07 22:00:00 +01:00
Sys_Error ( " Mem_Alloc: trashed clump sentinel 1 (alloc at %s:%d) \n " , filename , fileline ) ;
2007-11-09 22:00:00 +01:00
if ( clump - > sentinel2 ! = MEMCLUMP_SENTINEL )
2008-01-07 22:00:00 +01:00
Sys_Error ( " Mem_Alloc: trashed clump sentinel 2 (alloc at %s:%d) \n " , filename , fileline ) ;
2007-11-09 22:00:00 +01:00
if ( clump - > largestavailable > = needed )
{
largest = 0 ;
for ( i = 0 ; i < endbit ; i + + )
{
if ( clump - > bits [ i > > 5 ] & ( 1 < < ( i & 31 ) ) )
continue ;
k = i + needed ;
for ( j = i ; i < k ; i + + )
if ( clump - > bits [ i > > 5 ] & ( 1 < < ( i & 31 ) ) )
goto loopcontinue ;
goto choseclump ;
loopcontinue : ;
if ( largest < j - i )
largest = j - i ;
}
// since clump falsely advertised enough space (nothing wrong
// with that), update largest count to avoid wasting time in
// later allocations
clump - > largestavailable = largest ;
}
}
pool - > realsize + = sizeof ( memclump_t ) ;
clump = malloc ( sizeof ( memclump_t ) ) ;
2008-01-07 22:00:00 +01:00
if ( clump = = NULL ) Sys_Error ( " Mem_Alloc: out of memory (alloc at %s:%i) \n " , filename , fileline ) ;
2007-11-09 22:00:00 +01:00
memset ( clump , 0 , sizeof ( memclump_t ) ) ;
* clumpchainpointer = clump ;
clump - > sentinel1 = MEMCLUMP_SENTINEL ;
clump - > sentinel2 = MEMCLUMP_SENTINEL ;
clump - > chain = NULL ;
clump - > blocksinuse = 0 ;
clump - > largestavailable = MEMBITS - needed ;
j = 0 ;
choseclump :
mem = ( memheader_t * ) ( ( byte * ) clump - > block + j * MEMUNIT ) ;
mem - > clump = clump ;
clump - > blocksinuse + = needed ;
for ( i = j + needed ; j < i ; j + + ) clump - > bits [ j > > 5 ] | = ( 1 < < ( j & 31 ) ) ;
}
else
{
// big allocations are not clumped
pool - > realsize + = sizeof ( memheader_t ) + size + sizeof ( int ) ;
mem = ( memheader_t * ) malloc ( sizeof ( memheader_t ) + size + sizeof ( int ) ) ;
2008-01-07 22:00:00 +01:00
if ( mem = = NULL ) Sys_Error ( " Mem_Alloc: out of memory (alloc at %s:%i) \n " , filename , fileline ) ;
2007-11-09 22:00:00 +01:00
mem - > clump = NULL ;
}
mem - > filename = filename ;
mem - > fileline = fileline ;
mem - > size = size ;
mem - > pool = pool ;
mem - > sentinel1 = MEMHEADER_SENTINEL1 ;
// we have to use only a single byte for this sentinel, because it may not be aligned
// and some platforms can't use unaligned accesses
* ( ( byte * ) mem + sizeof ( memheader_t ) + mem - > size ) = MEMHEADER_SENTINEL2 ;
// append to head of list
mem - > next = pool - > chain ;
mem - > prev = NULL ;
pool - > chain = mem ;
if ( mem - > next ) mem - > next - > prev = mem ;
memset ( ( void * ) ( ( byte * ) mem + sizeof ( memheader_t ) ) , 0 , mem - > size ) ;
2007-11-14 22:00:00 +01:00
2007-11-09 22:00:00 +01:00
return ( void * ) ( ( byte * ) mem + sizeof ( memheader_t ) ) ;
}
static void _mem_freeblock ( memheader_t * mem , const char * filename , int fileline )
{
int i , firstblock , endblock ;
memclump_t * clump , * * clumpchainpointer ;
mempool_t * pool ;
2008-01-07 22:00:00 +01:00
if ( mem - > sentinel1 ! = MEMHEADER_SENTINEL1 ) Sys_Error ( " Mem_Free: trashed header sentinel 1 (alloc at %s:%i, free at %s:%i) \n " , mem - > filename , mem - > fileline , filename , fileline ) ;
2007-11-09 22:00:00 +01:00
if ( * ( ( byte * ) mem + sizeof ( memheader_t ) + mem - > size ) ! = MEMHEADER_SENTINEL2 )
2008-01-07 22:00:00 +01:00
Sys_Error ( " Mem_Free: trashed header sentinel 2 (alloc at %s:%i, free at %s:%i) \n " , mem - > filename , mem - > fileline , filename , fileline ) ;
2007-11-09 22:00:00 +01:00
pool = mem - > pool ;
// unlink memheader from doubly linked list
if ( ( mem - > prev ? mem - > prev - > next ! = mem : pool - > chain ! = mem ) | | ( mem - > next & & mem - > next - > prev ! = mem ) )
2008-01-07 22:00:00 +01:00
Sys_Error ( " Mem_Free: not allocated or double freed (free at %s:%i) \n " , filename , fileline ) ;
2007-11-09 22:00:00 +01:00
if ( mem - > prev ) mem - > prev - > next = mem - > next ;
else pool - > chain = mem - > next ;
if ( mem - > next ) mem - > next - > prev = mem - > prev ;
// memheader has been unlinked, do the actual free now
pool - > totalsize - = mem - > size ;
2008-01-03 22:00:00 +01:00
if ( ( clump = mem - > clump ) )
2007-11-09 22:00:00 +01:00
{
if ( clump - > sentinel1 ! = MEMCLUMP_SENTINEL )
2008-01-07 22:00:00 +01:00
Sys_Error ( " Mem_Free: trashed clump sentinel 1 (free at %s:%i) \n " , filename , fileline ) ;
2007-11-09 22:00:00 +01:00
if ( clump - > sentinel2 ! = MEMCLUMP_SENTINEL )
2008-01-07 22:00:00 +01:00
Sys_Error ( " Mem_Free: trashed clump sentinel 2 (free at %s:%i) \n " , filename , fileline ) ;
2007-11-09 22:00:00 +01:00
firstblock = ( ( byte * ) mem - ( byte * ) clump - > block ) ;
if ( firstblock & ( MEMUNIT - 1 ) )
2008-01-07 22:00:00 +01:00
Sys_Error ( " Mem_Free: address not valid in clump (free at %s:%i) \n " , filename , fileline ) ;
2007-11-09 22:00:00 +01:00
firstblock / = MEMUNIT ;
endblock = firstblock + ( ( sizeof ( memheader_t ) + mem - > size + sizeof ( int ) + ( MEMUNIT - 1 ) ) / MEMUNIT ) ;
clump - > blocksinuse - = endblock - firstblock ;
// could use &, but we know the bit is set
for ( i = firstblock ; i < endblock ; i + + )
clump - > bits [ i > > 5 ] - = ( 1 < < ( i & 31 ) ) ;
if ( clump - > blocksinuse < = 0 )
{
// unlink from chain
for ( clumpchainpointer = & pool - > clumpchain ; * clumpchainpointer ; clumpchainpointer = & ( * clumpchainpointer ) - > chain )
{
if ( * clumpchainpointer = = clump )
{
* clumpchainpointer = clump - > chain ;
break ;
}
}
pool - > realsize - = sizeof ( memclump_t ) ;
memset ( clump , 0xBF , sizeof ( memclump_t ) ) ;
2007-11-14 22:00:00 +01:00
free ( clump ) ;
2007-11-09 22:00:00 +01:00
}
else
{
// clump still has some allocations
// force re-check of largest available space on next alloc
clump - > largestavailable = MEMBITS - clump - > blocksinuse ;
}
}
else
{
pool - > realsize - = sizeof ( memheader_t ) + mem - > size + sizeof ( int ) ;
2007-11-14 22:00:00 +01:00
free ( mem ) ;
2007-11-09 22:00:00 +01:00
}
}
void _mem_free ( void * data , const char * filename , int fileline )
{
2008-01-07 22:00:00 +01:00
if ( data = = NULL ) Sys_Error ( " Mem_Free: data == NULL (called at %s:%i) \n " , filename , fileline ) ;
2007-11-09 22:00:00 +01:00
_mem_freeblock ( ( memheader_t * ) ( ( byte * ) data - sizeof ( memheader_t ) ) , filename , fileline ) ;
}
void * _mem_realloc ( byte * poolptr , void * memptr , size_t size , const char * filename , int fileline )
{
char * nb ;
memheader_t * memhdr ;
2008-08-15 22:00:00 +02:00
if ( size < = 0 ) return memptr ; // no need to reallocate
2008-10-20 22:00:00 +02:00
nb = _mem_alloc ( poolptr , size , filename , fileline ) ;
2007-11-09 22:00:00 +01:00
if ( memptr ) // first allocate?
{
2008-08-15 22:00:00 +02:00
size_t newsize ;
2007-11-09 22:00:00 +01:00
// get size of old block
memhdr = ( memheader_t * ) ( ( byte * ) memptr - sizeof ( memheader_t ) ) ;
2008-08-15 22:00:00 +02:00
newsize = memhdr - > size < size ? memhdr - > size : size ; // upper data can be trucnated!
_mem_copy ( nb , memptr , newsize , filename , fileline ) ;
2007-11-09 22:00:00 +01:00
_mem_free ( memptr , filename , fileline ) ; // free unused old block
}
return ( void * ) nb ;
}
void _mem_move ( byte * poolptr , void * * dest , void * src , size_t size , const char * filename , int fileline )
{
memheader_t * mem ;
void * memptr = * dest ;
2008-01-07 22:00:00 +01:00
if ( ! memptr ) Sys_Error ( " Mem_Move: dest == NULL (called at %s:%i) \n " , filename , fileline ) ;
if ( ! src ) Sys_Error ( " Mem_Move: src == NULL (called at %s:%i) \n " , filename , fileline ) ;
2007-11-09 22:00:00 +01:00
if ( size < = 0 )
{
// just free memory
_mem_free ( memptr , filename , fileline ) ;
* dest = src ; // swap blocks
return ;
}
mem = ( memheader_t * ) ( ( byte * ) memptr - sizeof ( memheader_t ) ) ; // get size of old block
if ( mem - > size ! = size )
{
_mem_free ( memptr , filename , fileline ) ; // release old buffer
memptr = _mem_alloc ( poolptr , size , filename , fileline ) ; // alloc new size
}
2008-01-28 22:00:00 +01:00
else memset ( memptr , 0 , size ) ; // no need to reallocate buffer
2007-11-09 22:00:00 +01:00
_mem_copy ( memptr , src , size , filename , fileline ) ; // move memory...
_mem_free ( src , filename , fileline ) ; // ...and free old pointer
* dest = memptr ;
}
byte * _mem_allocpool ( const char * name , const char * filename , int fileline )
{
mempool_t * pool ;
pool = ( mempool_t * ) malloc ( sizeof ( mempool_t ) ) ;
2008-01-07 22:00:00 +01:00
if ( pool = = NULL ) Sys_Error ( " Mem_AllocPool: out of memory (allocpool at %s:%i) \n " , filename , fileline ) ;
2008-01-28 22:00:00 +01:00
memset ( pool , 0 , sizeof ( mempool_t ) ) ;
2007-11-09 22:00:00 +01:00
// fill header
pool - > sentinel1 = MEMHEADER_SENTINEL1 ;
pool - > sentinel2 = MEMHEADER_SENTINEL1 ;
pool - > filename = filename ;
pool - > fileline = fileline ;
pool - > chain = NULL ;
pool - > totalsize = 0 ;
pool - > realsize = sizeof ( mempool_t ) ;
2007-11-10 22:00:00 +01:00
com_strncpy ( pool - > name , name , sizeof ( pool - > name ) ) ;
2007-11-09 22:00:00 +01:00
pool - > next = poolchain ;
poolchain = pool ;
2007-11-14 22:00:00 +01:00
MsgDev ( D_MEMORY , " Create pool: \" %s \" , at (%s:%i) \n " , pool - > name , filename , fileline ) ;
2007-11-09 22:00:00 +01:00
return ( byte * ) ( ( mempool_t * ) pool ) ;
}
void _mem_freepool ( byte * * poolptr , const char * filename , int fileline )
{
mempool_t * pool = ( mempool_t * ) ( ( byte * ) * poolptr ) ;
mempool_t * * chainaddress ;
if ( pool )
{
// unlink pool from chain
for ( chainaddress = & poolchain ; * chainaddress & & * chainaddress ! = pool ; chainaddress = & ( ( * chainaddress ) - > next ) ) ;
2008-01-07 22:00:00 +01:00
if ( * chainaddress ! = pool ) Sys_Error ( " Mem_FreePool: pool already free (freepool at %s:%i) \n " , filename , fileline ) ;
if ( pool - > sentinel1 ! = MEMHEADER_SENTINEL1 ) Sys_Error ( " Mem_FreePool: trashed pool sentinel 1 (allocpool at %s:%i, freepool at %s:%i) \n " , pool - > filename , pool - > fileline , filename , fileline ) ;
if ( pool - > sentinel2 ! = MEMHEADER_SENTINEL1 ) Sys_Error ( " Mem_FreePool: trashed pool sentinel 2 (allocpool at %s:%i, freepool at %s:%i) \n " , pool - > filename , pool - > fileline , filename , fileline ) ;
2007-11-09 22:00:00 +01:00
* chainaddress = pool - > next ;
2007-11-14 22:00:00 +01:00
MsgDev ( D_MEMORY , " Free pool: \" %s \" , at (%s:%i) \n " , pool - > name , filename , fileline ) ;
2007-11-09 22:00:00 +01:00
// free memory owned by the pool
while ( pool - > chain ) _mem_freeblock ( pool - > chain , filename , fileline ) ;
// free the pool itself
2008-01-28 22:00:00 +01:00
memset ( pool , 0xBF , sizeof ( mempool_t ) ) ;
2007-11-09 22:00:00 +01:00
free ( pool ) ;
* poolptr = NULL ;
}
}
void _mem_emptypool ( byte * poolptr , const char * filename , int fileline )
{
mempool_t * pool = ( mempool_t * ) ( ( byte * ) poolptr ) ;
2008-01-07 22:00:00 +01:00
if ( poolptr = = NULL ) Sys_Error ( " Mem_EmptyPool: pool == NULL (emptypool at %s:%i) \n " , filename , fileline ) ;
2007-11-09 22:00:00 +01:00
2008-01-07 22:00:00 +01:00
if ( pool - > sentinel1 ! = MEMHEADER_SENTINEL1 ) Sys_Error ( " Mem_EmptyPool: trashed pool sentinel 1 (allocpool at %s:%i, emptypool at %s:%i) \n " , pool - > filename , pool - > fileline , filename , fileline ) ;
if ( pool - > sentinel2 ! = MEMHEADER_SENTINEL1 ) Sys_Error ( " Mem_EmptyPool: trashed pool sentinel 2 (allocpool at %s:%i, emptypool at %s:%i) \n " , pool - > filename , pool - > fileline , filename , fileline ) ;
2007-11-09 22:00:00 +01:00
// free memory owned by the pool
while ( pool - > chain ) _mem_freeblock ( pool - > chain , filename , fileline ) ;
}
2007-12-17 22:00:00 +01:00
bool _mem_allocated ( mempool_t * pool , void * data )
{
memheader_t * header , * target ;
if ( pool )
{
// search only one pool
target = ( memheader_t * ) ( ( byte * ) data - sizeof ( memheader_t ) ) ;
for ( header = pool - > chain ; header ; header = header - > next )
if ( header = = target ) return true ;
}
else
{
// search all pools
for ( pool = poolchain ; pool ; pool = pool - > next )
if ( _mem_allocated ( pool , data ) )
return true ;
}
return false ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = =
Check pointer for memory
allocated by memlib . c
= = = = = = = = = = = = = = = = = = = = = = = =
*/
bool _is_allocated ( byte * poolptr , void * data )
{
mempool_t * pool = NULL ;
if ( poolptr ) pool = ( mempool_t * ) ( ( byte * ) poolptr ) ;
return _mem_allocated ( pool , data ) ;
}
byte * _mem_alloc_array ( byte * poolptr , size_t recordsize , int count , const char * filename , int fileline )
{
memarray_t * l = _mem_alloc ( poolptr , sizeof ( memarray_t ) , filename , fileline ) ;
l - > mempool = poolptr ;
l - > recordsize = recordsize ;
l - > count = count ;
return ( byte * ) ( ( memarray_t * ) l ) ;
}
void _mem_free_array ( byte * arrayptr , const char * filename , int fileline )
{
memarray_t * l = ( memarray_t * ) ( ( byte * ) arrayptr ) ;
size_t i ;
2008-01-07 22:00:00 +01:00
if ( l = = NULL ) Sys_Error ( " Mem_RemoveArray: array == NULL (called at %s:%i) \n " , filename , fileline ) ;
2007-12-17 22:00:00 +01:00
if ( l - > maxarrays )
{
for ( i = 0 ; i ! = l - > numarrays ; i + + )
_mem_free ( l - > arrays [ i ] . data , filename , fileline ) ;
_mem_free ( l - > arrays , filename , fileline ) ;
}
_mem_free ( l , filename , fileline ) ; // himself
}
void * _mem_alloc_array_element ( byte * arrayptr , const char * filename , int fileline )
{
memarray_t * l = ( memarray_t * ) ( ( byte * ) arrayptr ) ;
size_t i , j ;
2008-01-07 22:00:00 +01:00
if ( l = = NULL ) Sys_Error ( " Mem_AllocElement: array == NULL (called at %s:%i) \n " , filename , fileline ) ;
2007-12-17 22:00:00 +01:00
for ( i = 0 ; ; i + + )
{
if ( i = = l - > numarrays )
{
if ( l - > numarrays = = l - > maxarrays )
{
memcluster_t * oldarrays = l - > arrays ;
l - > maxarrays = max ( l - > maxarrays * 2 , 128 ) ;
l - > arrays = _mem_alloc ( l - > mempool , l - > maxarrays * sizeof ( * l - > arrays ) , filename , fileline ) ;
if ( oldarrays )
{
_mem_copy ( l - > arrays , oldarrays , l - > numarrays * sizeof ( * l - > arrays ) , filename , fileline ) ;
_mem_free ( oldarrays , filename , fileline ) ;
}
}
l - > arrays [ i ] . numflaggedrecords = 0 ;
l - > arrays [ i ] . data = _mem_alloc ( l - > mempool , ( l - > recordsize + 1 ) * l - > count , filename , fileline ) ;
l - > arrays [ i ] . allocflags = l - > arrays [ i ] . data + l - > recordsize * l - > count ;
l - > numarrays + + ;
}
if ( l - > arrays [ i ] . numflaggedrecords < l - > count )
{
for ( j = 0 ; j < l - > count ; j + + )
{
if ( ! l - > arrays [ i ] . allocflags [ j ] )
{
l - > arrays [ i ] . allocflags [ j ] = true ;
l - > arrays [ i ] . numflaggedrecords + + ;
return ( void * ) ( l - > arrays [ i ] . data + l - > recordsize * j ) ;
}
}
}
}
}
void _mem_free_array_element ( byte * arrayptr , void * element , const char * filename , int fileline )
{
size_t i , j ;
byte * p = ( byte * ) element ;
memarray_t * l = ( memarray_t * ) ( ( byte * ) arrayptr ) ;
2008-01-07 22:00:00 +01:00
if ( l = = NULL ) Sys_Error ( " Mem_FreeElement: array == NULL (called at %s:%i) \n " , filename , fileline ) ;
2007-12-17 22:00:00 +01:00
for ( i = 0 ; i ! = l - > numarrays ; i + + )
{
if ( p > = l - > arrays [ i ] . data & & p < ( l - > arrays [ i ] . data + l - > recordsize * l - > count ) )
{
j = ( p - l - > arrays [ i ] . data ) / l - > recordsize ;
if ( p ! = l - > arrays [ i ] . data + j * l - > recordsize )
Sys_Error ( " Mem_FreeArrayElement: no such element %p \n " , p ) ;
if ( ! l - > arrays [ i ] . allocflags [ j ] )
Sys_Error ( " Mem_FreeArrayElement: element %p is already free! \n " , p ) ;
l - > arrays [ i ] . allocflags [ j ] = false ;
l - > arrays [ i ] . numflaggedrecords - - ;
return ;
}
}
}
size_t _mem_array_size ( byte * arrayptr )
{
size_t i , j , k ;
memarray_t * l = ( memarray_t * ) ( ( byte * ) arrayptr ) ;
if ( l & & l - > numarrays )
{
i = l - > numarrays - 1 ;
for ( j = 0 , k = 0 ; k < l - > arrays [ i ] . numflaggedrecords ; j + + )
if ( l - > arrays [ i ] . allocflags [ j ] ) k + + ;
return l - > count * i + j ;
}
return 0 ;
}
void * _mem_get_array_element ( byte * arrayptr , size_t index )
{
size_t i , j ;
memarray_t * l = ( memarray_t * ) ( ( byte * ) arrayptr ) ;
if ( ! l ) return NULL ;
i = index / l - > count ;
j = index % l - > count ;
if ( i > = l - > numarrays | | ! l - > arrays [ i ] . allocflags [ j ] )
return NULL ;
return ( void * ) ( l - > arrays [ i ] . data + j * l - > recordsize ) ;
}
2008-07-31 22:00:00 +02:00
void _mem_checkheadersentinels ( void * data , const char * filename , int fileline )
2007-11-09 22:00:00 +01:00
{
memheader_t * mem ;
2008-01-07 22:00:00 +01:00
if ( data = = NULL ) Sys_Error ( " Mem_CheckSentinels: data == NULL (sentinel check at %s:%i) \n " , filename , fileline ) ;
2007-11-09 22:00:00 +01:00
mem = ( memheader_t * ) ( ( byte * ) data - sizeof ( memheader_t ) ) ;
if ( mem - > sentinel1 ! = MEMHEADER_SENTINEL1 )
2008-01-07 22:00:00 +01:00
Sys_Error ( " Mem_CheckSentinels: trashed header sentinel 1 (block allocated at %s:%i, sentinel check at %s:%i) \n " , mem - > filename , mem - > fileline , filename , fileline ) ;
2007-11-09 22:00:00 +01:00
if ( * ( ( byte * ) mem + sizeof ( memheader_t ) + mem - > size ) ! = MEMHEADER_SENTINEL2 )
2008-01-07 22:00:00 +01:00
Sys_Error ( " Mem_CheckSentinels: trashed header sentinel 2 (block allocated at %s:%i, sentinel check at %s:%i) \n " , mem - > filename , mem - > fileline , filename , fileline ) ;
2007-11-09 22:00:00 +01:00
}
2008-07-31 22:00:00 +02:00
static void _mem_checkclumpsentinels ( memclump_t * clump , const char * filename , int fileline )
2007-11-09 22:00:00 +01:00
{
// this isn't really very useful
if ( clump - > sentinel1 ! = MEMCLUMP_SENTINEL )
2008-01-07 22:00:00 +01:00
Sys_Error ( " Mem_CheckClumpSentinels: trashed sentinel 1 (sentinel check at %s:%i) \n " , filename , fileline ) ;
2007-11-09 22:00:00 +01:00
if ( clump - > sentinel2 ! = MEMCLUMP_SENTINEL )
2008-01-07 22:00:00 +01:00
Sys_Error ( " Mem_CheckClumpSentinels: trashed sentinel 2 (sentinel check at %s:%i) \n " , filename , fileline ) ;
2007-11-09 22:00:00 +01:00
}
void _mem_check ( const char * filename , int fileline )
{
memheader_t * mem ;
mempool_t * pool ;
memclump_t * clump ;
2007-11-14 22:00:00 +01:00
for ( pool = poolchain ; pool ; pool = pool - > next )
2007-11-09 22:00:00 +01:00
{
if ( pool - > sentinel1 ! = MEMHEADER_SENTINEL1 )
2008-01-07 22:00:00 +01:00
Sys_Error ( " Mem_CheckSentinelsGlobal: trashed pool sentinel 1 (allocpool at %s:%i, sentinel check at %s:%i) \n " , pool - > filename , pool - > fileline , filename , fileline ) ;
2007-11-09 22:00:00 +01:00
if ( pool - > sentinel2 ! = MEMHEADER_SENTINEL1 )
2008-01-07 22:00:00 +01:00
Sys_Error ( " Mem_CheckSentinelsGlobal: trashed pool sentinel 2 (allocpool at %s:%i, sentinel check at %s:%i) \n " , pool - > filename , pool - > fileline , filename , fileline ) ;
2007-11-09 22:00:00 +01:00
}
2007-11-14 22:00:00 +01:00
for ( pool = poolchain ; pool ; pool = pool - > next )
for ( mem = pool - > chain ; mem ; mem = mem - > next )
2007-11-09 22:00:00 +01:00
_mem_checkheadersentinels ( ( void * ) ( ( byte * ) mem + sizeof ( memheader_t ) ) , filename , fileline ) ;
2007-11-14 22:00:00 +01:00
for ( pool = poolchain ; pool ; pool = pool - > next )
for ( clump = pool - > clumpchain ; clump ; clump = clump - > chain )
2007-11-09 22:00:00 +01:00
_mem_checkclumpsentinels ( clump , filename , fileline ) ;
}
2007-12-17 22:00:00 +01:00
void _mem_printstats ( void )
{
size_t count = 0 , size = 0 , realsize = 0 ;
mempool_t * pool ;
Mem_Check ( ) ;
for ( pool = poolchain ; pool ; pool = pool - > next )
{
count + + ;
size + = pool - > totalsize ;
realsize + = pool - > realsize ;
}
Msg ( " ^3%lu^7 memory pools, totalling: ^1%s \n " , ( dword ) count , Mem_Pretify ( size ) ) ;
Msg ( " Total allocated size: ^1%s \n " , Mem_Pretify ( realsize ) ) ;
}
void _mem_printlist ( size_t minallocationsize )
{
mempool_t * pool ;
memheader_t * mem ;
Mem_Check ( ) ;
Msg ( " memory pool list: \n " " ^3size name \n " ) ;
for ( pool = poolchain ; pool ; pool = pool - > next )
{
Msg ( " %5luk (%5luk actual) %s (%+3li byte change) \n " , ( dword ) ( ( pool - > totalsize + 1023 ) / 1024 ) , ( dword ) ( ( pool - > realsize + 1023 ) / 1024 ) , pool - > name , ( long ) pool - > totalsize - pool - > lastchecksize ) ;
pool - > lastchecksize = pool - > totalsize ;
2008-07-31 22:00:00 +02:00
for ( mem = pool - > chain ; mem ; mem = mem - > next )
if ( mem - > size > = minallocationsize )
Msg ( " %10lu bytes allocated at %s:%i \n " , ( dword ) mem - > size , mem - > filename , mem - > fileline ) ;
2007-12-17 22:00:00 +01:00
}
}
2008-07-31 22:00:00 +02:00
void MemList_f ( void )
2007-12-17 22:00:00 +01:00
{
switch ( Cmd_Argc ( ) )
{
case 1 :
_mem_printlist ( 1 < < 30 ) ;
_mem_printstats ( ) ;
break ;
case 2 :
2008-08-06 22:00:00 +02:00
_mem_printlist ( com_atoi ( Cmd_Argv ( 1 ) ) * 1024 ) ;
2007-12-17 22:00:00 +01:00
_mem_printstats ( ) ;
break ;
default :
Msg ( " memlist: usage: memlist <all> \n " ) ;
break ;
}
}
2007-11-09 22:00:00 +01:00
/*
= = = = = = = = = = = = = = = = = = = = = = = =
Memory_Init
= = = = = = = = = = = = = = = = = = = = = = = =
*/
2007-11-10 22:00:00 +01:00
void Memory_Init ( void )
2007-11-09 22:00:00 +01:00
{
2007-11-11 22:00:00 +01:00
poolchain = NULL ; // init mem chain
Sys . basepool = Mem_AllocPool ( " Main pool " ) ;
2007-11-14 22:00:00 +01:00
Sys . stringpool = Mem_AllocPool ( " New string " ) ;
2007-11-10 22:00:00 +01:00
}
void Memory_Shutdown ( void )
{
2007-11-11 22:00:00 +01:00
Mem_FreePool ( & Sys . basepool ) ;
2007-11-14 22:00:00 +01:00
Mem_FreePool ( & Sys . stringpool ) ;
2007-12-17 22:00:00 +01:00
}
void Memory_Init_Commands ( void )
{
2008-07-31 22:00:00 +02:00
Cmd_AddCommand ( " memlist " , MemList_f , " prints memory pool information (or if used as memlist 5 lists individual allocations of 5K or larger, 0 lists all allocations) " ) ;
2007-11-09 22:00:00 +01:00
}