void _Mem_FreePool( mempool_t **pool, int musthave, int canthave, const char *filename, int fileline ) { mempool_t **chainAddress; #ifdef SHOW_NONFREED memheader_t *mem; #endif if( !( *pool ) ) return; if( musthave && ( ( ( *pool )->flags & musthave ) != musthave ) ) _Mem_Error( "Mem_FreePool: bad pool flags (musthave) (alloc at %s:%i)", filename, fileline ); if( canthave && ( ( *pool )->flags & canthave ) ) _Mem_Error( "Mem_FreePool: bad pool flags (canthave) (alloc at %s:%i)", filename, fileline ); // recurse into children // note that children will be freed no matter if their flags // do not match musthave\canthave pair while( ( *pool )->child ) { mempool_t *tmp = ( *pool )->child; _Mem_FreePool( &tmp, 0, 0, filename, fileline ); } assert( ( *pool )->sentinel1 == MEMHEADER_SENTINEL1 ); assert( ( *pool )->sentinel2 == MEMHEADER_SENTINEL1 ); if( ( *pool )->sentinel1 != MEMHEADER_SENTINEL1 ) _Mem_Error( "Mem_FreePool: trashed pool sentinel 1 (allocpool at %s:%i, freepool at %s:%i)", ( *pool )->filename, ( *pool )->fileline, filename, fileline ); if( ( *pool )->sentinel2 != MEMHEADER_SENTINEL1 ) _Mem_Error( "Mem_FreePool: trashed pool sentinel 2 (allocpool at %s:%i, freepool at %s:%i)", ( *pool )->filename, ( *pool )->fileline, filename, fileline ); #ifdef SHOW_NONFREED if( ( *pool )->chain ) Com_Printf( "Warning: Memory pool %s has resources that weren't freed:\n", ( *pool )->name ); for( mem = ( *pool )->chain; mem; mem = mem->next ) { Com_Printf( "%10i bytes allocated at %s:%i\n", mem->size, mem->filename, mem->fileline ); } #endif // unlink pool from chain if( ( *pool )->parent ) for( chainAddress = &( *pool )->parent->child; *chainAddress && *chainAddress != *pool; chainAddress = &( ( *chainAddress )->next ) ) ; else for( chainAddress = &poolChain; *chainAddress && *chainAddress != *pool; chainAddress = &( ( *chainAddress )->next ) ) ; if( *chainAddress != *pool ) _Mem_Error( "Mem_FreePool: pool already free (freepool at %s:%i)", filename, fileline ); while( ( *pool )->chain ) // free memory owned by the pool Mem_Free( (void *)( (qbyte *)( *pool )->chain + sizeof( memheader_t ) ) ); *chainAddress = ( *pool )->next; // free the pool itself #ifdef MEMTRASH memset( *pool, 0xBF, sizeof( mempool_t ) ); #endif free( *pool ); *pool = NULL; }
void *_Mem_AllocExt( mempool_t *pool, size_t size, size_t alignment, int z, int musthave, int canthave, const char *filename, int fileline ) { void *base; size_t realsize; memheader_t *mem; if( size <= 0 ) return NULL; // default to 16-bytes alignment if( !alignment ) alignment = MEMALIGNMENT_DEFAULT; if( pool == NULL ) _Mem_Error( "Mem_Alloc: pool == NULL (alloc at %s:%i)", filename, fileline ); if( musthave && ( ( pool->flags & musthave ) != musthave ) ) _Mem_Error( "Mem_Alloc: bad pool flags (musthave) (alloc at %s:%i)", filename, fileline ); if( canthave && ( pool->flags & canthave ) ) _Mem_Error( "Mem_Alloc: bad pool flags (canthave) (alloc at %s:%i)", filename, fileline ); if( developerMemory && developerMemory->integer ) Com_DPrintf( "Mem_Alloc: pool %s, file %s:%i, size %i bytes\n", pool->name, filename, fileline, size ); pool->totalsize += size; realsize = sizeof( memheader_t ) + size + alignment + sizeof( int ); pool->realsize += realsize; base = malloc( realsize ); if( base == NULL ) _Mem_Error( "Mem_Alloc: out of memory (alloc at %s:%i)", filename, fileline ); // calculate address that aligns the end of the memheader_t to the specified alignment mem = ( memheader_t * )((((size_t)base + sizeof( memheader_t ) + (alignment-1)) & ~(alignment-1)) - sizeof( memheader_t )); mem->baseaddress = base; mem->filename = filename; mem->fileline = fileline; mem->size = size; mem->realsize = realsize; 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 *( (qbyte *) 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( z ) memset( (void *)( (qbyte *) mem + sizeof( memheader_t ) ), 0, mem->size ); return (void *)( (qbyte *) mem + sizeof( memheader_t ) ); }
void _Mem_Free( void *data, int musthave, int canthave, const char *filename, int fileline ) { void *base; memheader_t *mem; mempool_t *pool; if( data == NULL ) //_Mem_Error( "Mem_Free: data == NULL (called at %s:%i)", filename, fileline ); return; mem = ( memheader_t * )( (qbyte *) data - sizeof( memheader_t ) ); assert( mem->sentinel1 == MEMHEADER_SENTINEL1 ); assert( *( (qbyte *) mem + sizeof( memheader_t ) + mem->size ) == MEMHEADER_SENTINEL2 ); if( mem->sentinel1 != MEMHEADER_SENTINEL1 ) _Mem_Error( "Mem_Free: trashed header sentinel 1 (alloc at %s:%i, free at %s:%i)", mem->filename, mem->fileline, filename, fileline ); if( *( (qbyte *)mem + sizeof( memheader_t ) + mem->size ) != MEMHEADER_SENTINEL2 ) _Mem_Error( "Mem_Free: trashed header sentinel 2 (alloc at %s:%i, free at %s:%i)", mem->filename, mem->fileline, filename, fileline ); pool = mem->pool; if( musthave && ( ( pool->flags & musthave ) != musthave ) ) _Mem_Error( "Mem_Free: bad pool flags (musthave) (alloc at %s:%i)", filename, fileline ); if( canthave && ( pool->flags & canthave ) ) _Mem_Error( "Mem_Free: bad pool flags (canthave) (alloc at %s:%i)", filename, fileline ); if( developerMemory && developerMemory->integer ) Com_DPrintf( "Mem_Free: pool %s, alloc %s:%i, free %s:%i, size %i bytes\n", pool->name, mem->filename, mem->fileline, filename, fileline, mem->size ); QMutex_Lock( memMutex ); // unlink memheader from doubly linked list if( ( mem->prev ? mem->prev->next != mem : pool->chain != mem ) || ( mem->next && mem->next->prev != mem ) ) _Mem_Error( "Mem_Free: not allocated or double freed (free at %s:%i)", filename, fileline ); 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; base = mem->baseaddress; pool->realsize -= mem->realsize; QMutex_Unlock( memMutex ); #ifdef MEMTRASH memset( mem, 0xBF, sizeof( memheader_t ) + mem->size + sizeof( int ) ); #endif free( base ); }
void _Mem_CheckSentinels( void *data, const char *filename, int fileline ) { memheader_t *mem; if( data == NULL ) _Mem_Error( "Mem_CheckSentinels: data == NULL (sentinel check at %s:%i)", filename, fileline ); mem = (memheader_t *)( (qbyte *) data - sizeof( memheader_t ) ); assert( mem->sentinel1 == MEMHEADER_SENTINEL1 ); assert( *( (qbyte *) mem + sizeof( memheader_t ) + mem->size ) == MEMHEADER_SENTINEL2 ); if( mem->sentinel1 != MEMHEADER_SENTINEL1 ) _Mem_Error( "Mem_CheckSentinels: trashed header sentinel 1 (block allocated at %s:%i, sentinel check at %s:%i)", mem->filename, mem->fileline, filename, fileline ); if( *( (qbyte *) mem + sizeof( memheader_t ) + mem->size ) != MEMHEADER_SENTINEL2 ) _Mem_Error( "Mem_CheckSentinels: trashed header sentinel 2 (block allocated at %s:%i, sentinel check at %s:%i)", mem->filename, mem->fileline, filename, fileline ); }
void _Mem_EmptyPool( mempool_t *pool, int musthave, int canthave, const char *filename, int fileline ) { mempool_t *child, *next; #ifdef SHOW_NONFREED memheader_t *mem; #endif if( pool == NULL ) _Mem_Error( "Mem_EmptyPool: pool == NULL (emptypool at %s:%i)", filename, fileline ); if( musthave && ( ( pool->flags & musthave ) != musthave ) ) _Mem_Error( "Mem_EmptyPool: bad pool flags (musthave) (alloc at %s:%i)", filename, fileline ); if( canthave && ( pool->flags & canthave ) ) _Mem_Error( "Mem_EmptyPool: bad pool flags (canthave) (alloc at %s:%i)", filename, fileline ); // recurse into children if( pool->child ) { for( child = pool->child; child; child = next ) { next = child->next; _Mem_EmptyPool( child, 0, 0, filename, fileline ); } } assert( pool->sentinel1 == MEMHEADER_SENTINEL1 ); assert( pool->sentinel2 == MEMHEADER_SENTINEL1 ); if( pool->sentinel1 != MEMHEADER_SENTINEL1 ) _Mem_Error( "Mem_EmptyPool: trashed pool sentinel 1 (allocpool at %s:%i, emptypool at %s:%i)", pool->filename, pool->fileline, filename, fileline ); if( pool->sentinel2 != MEMHEADER_SENTINEL1 ) _Mem_Error( "Mem_EmptyPool: trashed pool sentinel 2 (allocpool at %s:%i, emptypool at %s:%i)", pool->filename, pool->fileline, filename, fileline ); #ifdef SHOW_NONFREED if( pool->chain ) Com_Printf( "Warning: Memory pool %s has resources that weren't freed:\n", pool->name ); for( mem = pool->chain; mem; mem = mem->next ) { Com_Printf( "%10i bytes allocated at %s:%i\n", mem->size, mem->filename, mem->fileline ); } #endif while( pool->chain ) // free memory owned by the pool Mem_Free( (void *)( (qbyte *) pool->chain + sizeof( memheader_t ) ) ); }
mempool_t *_Mem_AllocPool( mempool_t *parent, const char *name, int flags, const char *filename, int fileline ) { mempool_t *pool; if( parent && ( parent->flags & MEMPOOL_TEMPORARY ) ) _Mem_Error( "Mem_AllocPool: nested temporary pools are not allowed (allocpool at %s:%i)", filename, fileline ); if( flags & MEMPOOL_TEMPORARY ) _Mem_Error( "Mem_AllocPool: tried to allocate temporary pool, use Mem_AllocTempPool instead (allocpool at %s:%i)", filename, fileline ); pool = ( mempool_t* )malloc( sizeof( mempool_t ) ); if( pool == NULL ) _Mem_Error( "Mem_AllocPool: out of memory (allocpool at %s:%i)", filename, fileline ); memset( pool, 0, sizeof( mempool_t ) ); pool->sentinel1 = MEMHEADER_SENTINEL1; pool->sentinel2 = MEMHEADER_SENTINEL1; pool->filename = filename; pool->fileline = fileline; pool->flags = flags; pool->chain = NULL; pool->parent = parent; pool->child = NULL; pool->totalsize = 0; pool->realsize = sizeof( mempool_t ); Q_strncpyz( pool->name, name, sizeof( pool->name ) ); if( parent ) { pool->next = parent->child; parent->child = pool; } else { pool->next = poolChain; poolChain = pool; } return pool; }
static void _Mem_CheckSentinelsPool( mempool_t *pool, const char *filename, int fileline ) { memheader_t *mem; mempool_t *child; // recurse into children if( pool->child ) { for( child = pool->child; child; child = child->next ) _Mem_CheckSentinelsPool( child, filename, fileline ); } assert( pool->sentinel1 == MEMHEADER_SENTINEL1 ); assert( pool->sentinel2 == MEMHEADER_SENTINEL1 ); if( pool->sentinel1 != MEMHEADER_SENTINEL1 ) _Mem_Error( "_Mem_CheckSentinelsPool: trashed pool sentinel 1 (allocpool at %s:%i, sentinel check at %s:%i)", pool->filename, pool->fileline, filename, fileline ); if( pool->sentinel2 != MEMHEADER_SENTINEL1 ) _Mem_Error( "_Mem_CheckSentinelsPool: trashed pool sentinel 2 (allocpool at %s:%i, sentinel check at %s:%i)", pool->filename, pool->fileline, filename, fileline ); for( mem = pool->chain; mem; mem = mem->next ) _Mem_CheckSentinels( (void *)( (qbyte *) mem + sizeof( memheader_t ) ), filename, fileline ); }
// FIXME: rewrite this? void *_Mem_Realloc( void *data, size_t size, const char *filename, int fileline ) { void *newdata; memheader_t *mem; if( data == NULL ) _Mem_Error( "Mem_Realloc: data == NULL (called at %s:%i)", filename, fileline ); if( size <= 0 ) { Mem_Free( data ); return NULL; } mem = ( memheader_t * )( (qbyte *) data - sizeof( memheader_t ) ); if( size <= mem->size ) return data; newdata = Mem_AllocExt( mem->pool, size, 0 ); memcpy( newdata, data, mem->size ); Mem_Free( data ); return newdata; }