Browse Source

engine: zone: refactoring

master
Alibek Omarov 10 months ago
parent
commit
6cef6f6a75
  1. 309
      engine/common/zone.c

309
engine/common/zone.c

@ -93,116 +93,166 @@ static mempool_t *Mem_FindPool( poolhandle_t poolptr )
} }
#endif #endif
void *_Mem_Alloc( poolhandle_t poolptr, size_t size, qboolean clear, const char *filename, int fileline ) static inline void Mem_PoolAdd( mempool_t *pool, size_t size )
{ {
memheader_t *mem; pool->totalsize += size;
mempool_t *pool; pool->realsize += sizeof( memheader_t ) + size + sizeof( byte );
}
if( size <= 0 )
return NULL;
if( !poolptr )
{
Sys_Error( "Mem_Alloc: pool == NULL (alloc at %s:%i)\n", filename, fileline );
return NULL;
}
pool = Mem_FindPool( poolptr ); static inline void Mem_PoolSubtract( mempool_t *pool, size_t size )
{
pool->totalsize -= size;
pool->realsize -= sizeof( memheader_t ) + size + sizeof( byte );
}
pool->totalsize += size; static inline void Mem_PoolLinkAlloc( mempool_t *pool, memheader_t *mem )
{
mem->next = pool->chain;
if( mem->next ) mem->next->prev = mem;
pool->chain = mem;
mem->prev = NULL;
mem->pool = pool;
}
// big allocations are not clumped static inline void Mem_PoolUnlinkAlloc( mempool_t *pool, memheader_t *mem )
pool->realsize += sizeof( memheader_t ) + size + sizeof( size_t ); {
mem = (memheader_t *)Q_malloc( sizeof( memheader_t ) + size + sizeof( size_t )); if( mem->next ) mem->next->prev = mem->prev;
if( mem == NULL ) if( mem->prev ) mem->prev->next = mem->next;
{ else pool->chain = mem->next;
Sys_Error( "Mem_Realloc: out of memory (alloc size %s at %s:%i)\n", Q_memprint( size ), filename, fileline ); mem->pool = NULL;
return NULL; }
}
static inline void Mem_InitAlloc( memheader_t *mem, size_t size, const char *filename, int fileline )
{
mem->size = size;
mem->filename = filename; mem->filename = filename;
mem->fileline = fileline; mem->fileline = fileline;
mem->size = size;
mem->pool = pool;
mem->sentinel1 = MEMHEADER_SENTINEL1; 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; *((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;
if( clear )
memset((void *)((byte *)mem + sizeof( memheader_t )), 0, mem->size );
return (void *)((byte *)mem + sizeof( memheader_t ));
} }
static const char *Mem_CheckFilename( const char *filename ) static const char *Mem_CheckFilename( const char *filename )
{ {
static const char *dummy = "<corrupted>\0"; static const char *dummy = "<corrupted>\0";
const char *out = filename;
int i;
if( !COM_CheckString( out )) if( !COM_CheckString( filename ))
return dummy; return dummy;
for( i = 0; i < MAX_OSPATH; i++, out++ ) if( memchr( filename, '\0', MAX_OSPATH ) != NULL )
{ return filename;
if( *out == '\0' )
return filename; // valid name
}
return dummy; return dummy;
} }
static void Mem_FreeBlock( memheader_t *mem, const char *filename, int fileline ) static qboolean Mem_CheckAllocHeader( const char *func, const memheader_t *mem, const char *filename, int fileline )
{ {
mempool_t *pool; const char *memfilename;
if( mem->sentinel1 != MEMHEADER_SENTINEL1 ) if( mem->sentinel1 != MEMHEADER_SENTINEL1 )
{ {
mem->filename = Mem_CheckFilename( mem->filename ); // make sure what we don't crash var_args memfilename = Mem_CheckFilename( mem->filename );
Sys_Error( "Mem_Free: trashed header sentinel 1 (alloc at %s:%i, free at %s:%i)\n", mem->filename, mem->fileline, filename, fileline ); Sys_Error( "%s: trashed header sentinel 1 (alloc at %s:%i, check at %s:%i)\n", func, memfilename, mem->fileline, filename, fileline );
return false;
} }
if( *((byte *)mem + sizeof( memheader_t ) + mem->size ) != MEMHEADER_SENTINEL2 ) if( *((byte *)mem + sizeof( memheader_t ) + mem->size ) != MEMHEADER_SENTINEL2 )
{ {
mem->filename = Mem_CheckFilename( mem->filename ); // make sure what we don't crash var_args memfilename = Mem_CheckFilename( mem->filename ); // make sure what we don't crash var_args
Sys_Error( "Mem_Free: trashed header sentinel 2 (alloc at %s:%i, free at %s:%i)\n", mem->filename, mem->fileline, filename, fileline ); Sys_Error( "%s: trashed header sentinel 2 (alloc at %s:%i, check at %s:%i)\n", func, memfilename, mem->fileline, filename, fileline );
return false;
} }
return true;
}
static qboolean Mem_CheckPool( const char *func, const mempool_t *pool, const char *filename, int fileline )
{
if( pool->sentinel1 != MEMHEADER_SENTINEL1 )
{
Sys_Error( "%s: trashed pool sentinel 1 (allocpool at %s:%i, freepool at %s:%i)\n", func, pool->filename, pool->fileline, filename, fileline );
return false;
}
if( pool->sentinel2 != MEMHEADER_SENTINEL1 )
{
Sys_Error( "%s: trashed pool sentinel 2 (allocpool at %s:%i, freepool at %s:%i)\n", func, pool->filename, pool->fileline, filename, fileline );
return false;
}
return true;
}
void *_Mem_Alloc( poolhandle_t poolptr, size_t size, qboolean clear, const char *filename, int fileline )
{
memheader_t *mem;
mempool_t *pool;
if( size <= 0 )
return NULL;
if( !poolptr )
{
Sys_Error( "%s: pool == NULL (alloc at %s:%i)\n", __func__, filename, fileline );
return NULL;
}
mem = (memheader_t *)Q_malloc( sizeof( memheader_t ) + size + sizeof( byte ));
if( mem == NULL )
{
Sys_Error( "%s: out of memory (alloc size %s at %s:%i)\n", __func__, Q_memprint( size ), filename, fileline );
return NULL;
}
Mem_InitAlloc( mem, size, filename, fileline );
pool = Mem_FindPool( poolptr );
Mem_PoolAdd( pool, size );
Mem_PoolLinkAlloc( pool, mem );
if( clear )
memset((void *)((byte *)mem + sizeof( memheader_t )), 0, mem->size );
return (void *)((byte *)mem + sizeof( memheader_t ));
}
static void Mem_FreeBlock( memheader_t *mem, const char *filename, int fileline )
{
mempool_t *pool;
if( !Mem_CheckAllocHeader( __func__, mem, filename, fileline ))
return;
pool = mem->pool; pool = mem->pool;
// unlink memheader from doubly linked list // unlink memheader from doubly linked list
if(( mem->prev ? mem->prev->next != mem : pool->chain != mem ) || ( mem->next && mem->next->prev != mem )) if(( mem->prev ? mem->prev->next != mem : pool->chain != mem ) || ( mem->next && mem->next->prev != mem ))
Sys_Error( "Mem_Free: not allocated or double freed (free at %s:%i)\n", filename, fileline ); {
Sys_Error( "%s: not allocated or double freed (free at %s:%i)\n", __func__, filename, fileline );
if( mem->prev ) mem->prev->next = mem->next; return;
else pool->chain = mem->next; }
if( mem->next )
mem->next->prev = mem->prev;
// memheader has been unlinked, do the actual free now Mem_PoolSubtract( pool, mem->size );
pool->totalsize -= mem->size; Mem_PoolUnlinkAlloc( pool, mem );
pool->realsize -= sizeof( memheader_t ) + mem->size + sizeof( size_t );
Q_free( mem ); Q_free( mem );
} }
void _Mem_Free( void *data, const char *filename, int fileline ) void _Mem_Free( void *data, const char *filename, int fileline )
{ {
if( data == NULL ) Sys_Error( "Mem_Free: data == NULL (called at %s:%i)\n", filename, fileline ); if( data == NULL )
{
Sys_Error( "Mem_Free: data == NULL (called at %s:%i)\n", filename, fileline );
return;
}
Mem_FreeBlock((memheader_t *)((byte *)data - sizeof( memheader_t )), filename, fileline ); Mem_FreeBlock((memheader_t *)((byte *)data - sizeof( memheader_t )), filename, fileline );
} }
void *_Mem_Realloc( poolhandle_t poolptr, void *data, size_t size, qboolean clear, const char *filename, int fileline ) void *_Mem_Realloc( poolhandle_t poolptr, void *data, size_t size, qboolean clear, const char *filename, int fileline )
{ {
memheader_t *mem; memheader_t *mem;
mempool_t *pool, *oldpool; mempool_t *pool;
size_t newsize, oldsize; size_t oldsize;
char *nb;
if( size <= 0 ) if( size <= 0 )
return data; // no need to reallocate return data; // no need to reallocate
@ -218,87 +268,51 @@ void *_Mem_Realloc( poolhandle_t poolptr, void *data, size_t size, qboolean clea
mem = (memheader_t *)((byte *)data - sizeof( memheader_t )); mem = (memheader_t *)((byte *)data - sizeof( memheader_t ));
if( mem->sentinel1 != MEMHEADER_SENTINEL1 ) if( !Mem_CheckAllocHeader( "Mem_Realloc", mem, filename, fileline ))
{
mem->filename = Mem_CheckFilename( mem->filename ); // make sure what we don't crash var_args
Sys_Error( "Mem_Realloc: trashed header sentinel 1 (alloc at %s:%i, realloc at %s:%i)\n", mem->filename, mem->fileline, filename, fileline );
return NULL; return NULL;
}
if( *((byte *)mem + sizeof( memheader_t ) + mem->size ) != MEMHEADER_SENTINEL2 )
{
mem->filename = Mem_CheckFilename( mem->filename ); // make sure what we don't crash var_args
Sys_Error( "Mem_Realloc: trashed header sentinel 2 (alloc at %s:%i, realloc at %s:%i)\n", mem->filename, mem->fileline, filename, fileline );
return NULL;
}
oldsize = mem->size; oldsize = mem->size;
oldpool = mem->pool;
if( size == oldsize ) if( size == oldsize )
return data; return data;
#if XASH_CUSTOM_SWAP #if XASH_CUSTOM_SWAP
nb = _Mem_Alloc( poolptr, size, clear, filename, fileline ); {
char *nb = _Mem_Alloc( poolptr, size, clear, filename, fileline );
newsize = mem->size < size ? mem->size : size; // upper data can be trucnated! size_t newsize = mem->size < size ? mem->size : size; // upper data can be trucnated!
memcpy( nb, data, newsize ); memcpy( nb, data, newsize );
_Mem_Free( data, filename, fileline ); // free unused old block _Mem_Free( data, filename, fileline ); // free unused old block
return nb; return nb;
}
#else // XASH_CUSTOM_SWAP #else // XASH_CUSTOM_SWAP
pool = Mem_FindPool( poolptr ); pool = Mem_FindPool( poolptr );
mem = realloc( mem, sizeof( memheader_t ) + size + sizeof( size_t )); mem = realloc( mem, sizeof( memheader_t ) + size + sizeof( byte ));
if( mem == NULL ) if( mem == NULL )
{ {
Sys_Error( "Mem_Realloc: out of memory (alloc size %s at %s:%i)\n", Q_memprint( size ), filename, fileline ); Sys_Error( "Mem_Realloc: out of memory (alloc size %s at %s:%i)\n", Q_memprint( size ), filename, fileline );
return NULL; return NULL;
} }
pool->totalsize -= oldsize; Mem_PoolSubtract( pool, oldsize );
pool->realsize -= sizeof( memheader_t ) + oldsize + sizeof( size_t ); Mem_PoolAdd( pool, size );
pool->totalsize += size; Mem_InitAlloc( mem, size, filename, fileline );
pool->realsize += sizeof( memheader_t ) + size + sizeof( size_t );
mem->filename = filename;
mem->fileline = fileline;
mem->size = size;
// if allocation was migrated from one pool to another // if allocation was migrated from one pool to another
// (this is possible with original Mem_Realloc func) // (this is possible with original Mem_Realloc func)
if( oldpool != pool ) if( unlikely( mem->pool != pool ))
{ {
// unlink from old pool Mem_PoolUnlinkAlloc( mem->pool, mem );
if( mem->prev ) Mem_PoolLinkAlloc( pool, mem );
mem->prev->next = mem->next;
else pool->chain = mem->next;
if( mem->next )
mem->next->prev = mem->prev;
// attach to new
mem->next = pool->chain;
mem->prev = NULL;
pool->chain = mem;
if( mem->next )
mem->next->prev = mem;
} }
else else
{ {
// simply update pointers if( mem->next ) mem->next->prev = mem;
if( mem->prev ) if( mem->prev ) mem->prev->next = mem;
mem->prev->next = mem;
else pool->chain = mem; else pool->chain = mem;
if( mem->next )
mem->next->prev = mem;
} }
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;
// clear new memory // clear new memory
if( clear && size > oldsize ) if( clear && size > oldsize )
memset((byte *)mem + sizeof( memheader_t ) + oldsize, 0, size - oldsize ); memset((byte *)mem + sizeof( memheader_t ) + oldsize, 0, size - oldsize );
@ -349,8 +363,7 @@ void _Mem_FreePool( poolhandle_t *poolptr, const char *filename, int fileline )
// unlink pool from chain // unlink pool from chain
for( chainaddress = &poolchain; *chainaddress && *chainaddress != pool; chainaddress = &((*chainaddress)->next)); for( chainaddress = &poolchain; *chainaddress && *chainaddress != pool; chainaddress = &((*chainaddress)->next));
if( *chainaddress != pool ) Sys_Error( "Mem_FreePool: pool already free (freepool at %s:%i)\n", filename, fileline ); 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 ); Mem_CheckPool( "Mem_FreePool", pool, 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 );
*chainaddress = pool->next; *chainaddress = pool->next;
// free memory owned by the pool // free memory owned by the pool
@ -367,8 +380,7 @@ void _Mem_EmptyPool( poolhandle_t poolptr, const char *filename, int fileline )
mempool_t *pool = Mem_FindPool( poolptr ); mempool_t *pool = Mem_FindPool( poolptr );
if( !poolptr ) Sys_Error( "Mem_EmptyPool: pool == NULL (emptypool at %s:%i)\n", filename, fileline ); if( !poolptr ) Sys_Error( "Mem_EmptyPool: pool == NULL (emptypool at %s:%i)\n", filename, fileline );
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 ); Mem_CheckPool( "Mem_FreePool", pool, 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 );
// free memory owned by the pool // free memory owned by the pool
while( pool->chain ) Mem_FreeBlock( pool->chain, filename, fileline ); while( pool->chain ) Mem_FreeBlock( pool->chain, filename, fileline );
@ -383,14 +395,19 @@ static qboolean Mem_CheckAlloc( mempool_t *pool, void *data )
// search only one pool // search only one pool
target = (memheader_t *)((byte *)data - sizeof( memheader_t )); target = (memheader_t *)((byte *)data - sizeof( memheader_t ));
for( header = pool->chain; header; header = header->next ) for( header = pool->chain; header; header = header->next )
if( header == target ) return true; {
if( header == target )
return true;
}
} }
else else
{ {
// search all pools // search all pools
for( pool = poolchain; pool; pool = pool->next ) for( pool = poolchain; pool; pool = pool->next )
{
if( Mem_CheckAlloc( pool, data )) if( Mem_CheckAlloc( pool, data ))
return true; return true;
}
} }
return false; return false;
} }
@ -403,31 +420,11 @@ Check pointer for memory
qboolean Mem_IsAllocatedExt( poolhandle_t poolptr, void *data ) qboolean Mem_IsAllocatedExt( poolhandle_t poolptr, void *data )
{ {
mempool_t *pool = NULL; mempool_t *pool = NULL;
if( poolptr ) pool = Mem_FindPool( poolptr );
return Mem_CheckAlloc( pool, data );
}
static void Mem_CheckHeaderSentinels( void *data, const char *filename, int fileline )
{
memheader_t *mem;
if( data == NULL ) if( poolptr )
Sys_Error( "Mem_CheckSentinels: data == NULL (sentinel check at %s:%i)\n", filename, fileline ); pool = Mem_FindPool( poolptr );
mem = (memheader_t *)((byte *) data - sizeof(memheader_t));
if( mem->sentinel1 != MEMHEADER_SENTINEL1 )
{
mem->filename = Mem_CheckFilename( mem->filename ); // make sure what we don't crash var_args
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 );
}
if( *((byte *)mem + sizeof(memheader_t) + mem->size) != MEMHEADER_SENTINEL2 ) return Mem_CheckAlloc( pool, data );
{
mem->filename = Mem_CheckFilename( mem->filename ); // make sure what we don't crash var_args
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 );
}
} }
void _Mem_Check( const char *filename, int fileline ) void _Mem_Check( const char *filename, int fileline )
@ -436,16 +433,11 @@ void _Mem_Check( const char *filename, int fileline )
mempool_t *pool; mempool_t *pool;
for( pool = poolchain; pool; pool = pool->next ) for( pool = poolchain; pool; pool = pool->next )
{ Mem_CheckPool( "Mem_CheckSentinels", pool, filename, fileline );
if( pool->sentinel1 != MEMHEADER_SENTINEL1 )
Sys_Error( "Mem_CheckSentinelsGlobal: trashed pool sentinel 1 (allocpool at %s:%i, sentinel check at %s:%i)\n", pool->filename, pool->fileline, filename, fileline );
if( pool->sentinel2 != MEMHEADER_SENTINEL1 )
Sys_Error( "Mem_CheckSentinelsGlobal: trashed pool sentinel 2 (allocpool at %s:%i, sentinel check at %s:%i)\n", pool->filename, pool->fileline, filename, fileline );
}
for( pool = poolchain; pool; pool = pool->next ) for( pool = poolchain; pool; pool = pool->next )
for( mem = pool->chain; mem; mem = mem->next ) for( mem = pool->chain; mem; mem = mem->next )
Mem_CheckHeaderSentinels((void *)((byte *) mem + sizeof(memheader_t)), filename, fileline ); Mem_CheckAllocHeader( "Mem_CheckSentinels", mem, filename, fileline );
} }
void Mem_PrintStats( void ) void Mem_PrintStats( void )
@ -472,28 +464,31 @@ void Mem_PrintList( size_t minallocationsize )
Mem_Check(); Mem_Check();
Con_Printf( "memory pool list:\n"" ^3size name\n"); Con_Printf( "memory pool list:\n" );
Con_Printf( "\t^3size\t\t\t\tname\n");
for( pool = poolchain; pool; pool = pool->next ) for( pool = poolchain; pool; pool = pool->next )
{ {
long changed_size = (long)pool->totalsize - (long)pool->lastchecksize; long changed_size = (long)pool->totalsize - (long)pool->lastchecksize;
// poolnames can contain color symbols, make sure what color is reset // poolnames can contain color symbols, make sure what color is reset
if( changed_size != 0 ) if( pool->lastchecksize != 0 && changed_size != 0 )
{ {
char sign = (changed_size < 0) ? '-' : '+'; char sign = (changed_size < 0) ? '-' : '+';
Con_Printf( "%10s (%10s actual) %s (^7%c%s change)\n", Q_memprint( pool->totalsize ), Q_memprint( pool->realsize ), Con_Printf( "%10s (%10s real)\t%s (^7%c%s change)\n", Q_memprint( pool->totalsize ), Q_memprint( pool->realsize ),
pool->name, sign, Q_memprint( abs( changed_size ))); pool->name, sign, Q_memprint( abs( changed_size )));
} }
else else
{ {
Con_Printf( "%5s (%5s actual) %s\n", Q_memprint( pool->totalsize ), Q_memprint( pool->realsize ), pool->name ); Con_Printf( "%10s (%10s real)\t%s\n", Q_memprint( pool->totalsize ), Q_memprint( pool->realsize ), pool->name );
} }
pool->lastchecksize = pool->totalsize; pool->lastchecksize = pool->totalsize;
for( mem = pool->chain; mem; mem = mem->next ) for( mem = pool->chain; mem; mem = mem->next )
{
if( mem->size >= minallocationsize ) if( mem->size >= minallocationsize )
Con_Printf( "%10s allocated at %s:%i\n", Q_memprint( mem->size ), mem->filename, mem->fileline ); Con_Printf( "%10s allocated at %s:%i\n", Q_memprint( mem->size ), mem->filename, mem->fileline );
}
} }
} }

Loading…
Cancel
Save