quake4-sdk/source/idlib/rvHeapArena.cpp

304 lines
6.1 KiB
C++
Raw Normal View History

2007-06-15 00:00:00 +00:00
//
// rvHeapArena.cpp - Heap arena object that manages a set of heaps
// Date: 12/13/04
// Created by: Dwight Luetscher
//
#include "../idlib/precompiled.h"
#pragma hdrstop
#ifdef _RV_MEM_SYS_SUPPORT
// rvHeapArena
//
// constructor
rvHeapArena::rvHeapArena()
{
// ResetValues(); do this in the Init() call instead (due to the fact that other constructors could call rvHeapArena::Init() before this constructor is called)
}
// ~rvHeapArena
//
// destructor
rvHeapArena::~rvHeapArena()
{
Shutdown();
}
// Init
//
// initializes this heap arena for use
void rvHeapArena::Init( )
{
if ( m_isInitialized )
{
return;
}
ResetValues();
m_isInitialized = true;
// create the critical section used by this heap arena
InitializeCriticalSection( &m_criticalSection );
}
// Shutdown
//
// releases this heap arena from use (shutting down all associated heaps)
void rvHeapArena::Shutdown( )
{
// shutdown each heap from this arena's list
rvHeap *curHeap = m_heapList, *nextHeap;
while ( curHeap != NULL )
{
nextHeap = curHeap->GetNext();
curHeap->Shutdown();
curHeap = nextHeap;
}
DeleteCriticalSection( &m_criticalSection );
ResetValues();
}
// ResetValues
//
// resets the data members to their pre-initialized state
void rvHeapArena::ResetValues( )
{
memset( m_heapStack, 0, sizeof(m_heapStack) );
memset( &m_criticalSection, 0, sizeof(m_criticalSection) );
m_tos = -1;
m_heapList = NULL;
m_isInitialized = false;
}
// Push
//
// pushes the given heap onto the top of the stack making it the active one for this arena
void rvHeapArena::Push( rvHeap &newActiveHeap )
{
EnterArenaCriticalSection();
assert( newActiveHeap.GetArena() == this );
assert(m_tos+1 < maxHeapStackDepth); // stack overflow?
if (m_tos+1 < maxHeapStackDepth)
{
m_heapStack[++m_tos] = &newActiveHeap;
}
ExitArenaCriticalSection();
}
// Pop
//
// pops the top of the stack, restoring the previous heap as the active heap for this arena
void rvHeapArena::Pop( )
{
EnterArenaCriticalSection();
assert(m_tos > -1); // stack underflow?
if (m_tos > -1)
{
m_tos--;
}
ExitArenaCriticalSection();
}
// GetHeap
//
// returns: the heap that the given allocation was made from, NULL for none
rvHeap *rvHeapArena::GetHeap( void *p )
{
EnterArenaCriticalSection();
if ( !m_isInitialized )
{
ExitArenaCriticalSection();
return NULL;
}
rvHeap *curHeap = m_heapList;
while ( curHeap != NULL && !curHeap->DoesAllocBelong(p) )
{
curHeap = curHeap->GetNext();
}
ExitArenaCriticalSection();
return curHeap;
}
// Allocate
//
// allocates the given amount of memory from this arena.
void *rvHeapArena::Allocate( unsigned int sizeBytes, int debugTag )
{
rvHeap *curHeap;
EnterArenaCriticalSection();
assert( m_tos >= 0 && m_tos < maxHeapStackDepth );
if ( m_tos < 0 )
{
ExitArenaCriticalSection();
return NULL;
}
curHeap = m_heapStack[ m_tos ];
ExitArenaCriticalSection();
return curHeap->Allocate( sizeBytes, debugTag );
}
// Allocate16
//
// allocates the given amount of memory from this arena,
// aligned on a 16-byte boundary.
void *rvHeapArena::Allocate16( unsigned int sizeBytes, int debugTag )
{
rvHeap *curHeap;
EnterArenaCriticalSection();
assert( m_tos >= 0 && m_tos < maxHeapStackDepth );
if ( m_tos < 0 )
{
ExitArenaCriticalSection();
return NULL;
}
curHeap = m_heapStack[ m_tos ];
ExitArenaCriticalSection();
return curHeap->Allocate16( sizeBytes, debugTag );
}
// Free
//
// free memory back to this arena
void rvHeapArena::Free( void *p )
{
rvHeap *heap = GetHeap( p ); // arena critical section protection is in GetHeap()
if (heap != NULL)
{
heap->Free( p );
}
}
// Msize
//
// returns: the size, in bytes, of the allocation at the given address (including header, alignment bytes, etc).
int rvHeapArena::Msize( void *p )
{
rvHeap *heap = GetHeap( p ); // arena critical section protection is in GetHeap()
if (heap != NULL)
{
return heap->Msize( p );
}
return 0;
}
// InitHeap
//
// initializes the given heap to be under the care of this arena
void rvHeapArena::InitHeap( rvHeap &newActiveHeap )
{
assert( newActiveHeap.GetArena() == NULL );
newActiveHeap.SetArena( this );
newActiveHeap.SetNext( m_heapList );
m_heapList = &newActiveHeap;
}
// ShutdownHeap
//
// releases the given heap from the care of this arena
void rvHeapArena::ShutdownHeap( rvHeap &activeHeap )
{
int stackPos, copyPos;
assert( activeHeap.GetArena() == this );
activeHeap.SetArena( NULL );
// make sure that the heap is removed from the stack
for ( stackPos = 0; stackPos <= m_tos; stackPos++ )
{
if ( m_heapStack[stackPos] == &activeHeap )
{
for ( copyPos = stackPos; copyPos < m_tos; copyPos++ )
{
m_heapStack[copyPos] = m_heapStack[copyPos+1];
}
m_tos--;
}
}
// remove the heap from this arena's list
rvHeap *curHeap = m_heapList, * prevHeap = NULL;
while ( curHeap != NULL )
{
if ( curHeap == &activeHeap )
{
if ( NULL == prevHeap )
{
m_heapList = m_heapList->GetNext();
}
else
{
prevHeap->SetNext( curHeap->GetNext() );
}
break;
}
prevHeap = curHeap;
curHeap = curHeap->GetNext();
}
}
// GetNextHeap
//
// returns: that follows the given one (associated with this arena), NULL for none
rvHeap *rvHeapArena::GetNextHeap( rvHeap &rfPrevHeap )
{
rvHeap *nextHeap;
EnterArenaCriticalSection();
if ( rfPrevHeap.GetArena() != this )
{
nextHeap = NULL;
}
else
{
nextHeap = rfPrevHeap.GetNext();
}
ExitArenaCriticalSection();
return nextHeap;
}
// GetTagStats
//
// returns: the total stats for a particular tag type (across all heaps managed by this arena)
void rvHeapArena::GetTagStats(int tag, int &num, int &size, int &peak)
{
int curPeak;
assert( tag < MA_MAX );
EnterArenaCriticalSection();
num = size = peak = 0;
rvHeap *curHeap = m_heapList;
while ( curHeap != NULL )
{
num += curHeap->GetNumAllocationsByTag( (Mem_Alloc_Types_t) tag );
size += curHeap->GetBytesAllocatedByTag( (Mem_Alloc_Types_t) tag );
curPeak = curHeap->GetPeekBytesAllocatedByTag( (Mem_Alloc_Types_t) tag );
if ( curPeak > peak )
{
peak = curPeak;
}
curHeap = curHeap->GetNext();
}
ExitArenaCriticalSection();
}
#endif // #ifdef _RV_MEM_SYS_SUPPORT