|
|
// Ruler
// 1 2 3 4 5 6 7 8
//345678901234567890123456789012345678901234567890123456789012345678901234567890
/********************************************************************/ /* */ /* The standard layout. */ /* */ /* The standard layout for 'cpp' files in this code is as */ /* follows: */ /* */ /* 1. Include files. */ /* 2. Constants local to the class. */ /* 3. Data structures local to the class. */ /* 4. Data initializations. */ /* 5. Static functions. */ /* 6. Class functions. */ /* */ /* The constructor is typically the first function, class */ /* member functions appear in alphabetical order with the */ /* destructor appearing at the end of the file. Any section */ /* or function this is not required is simply omitted. */ /* */ /********************************************************************/
#include "InterfacePCH.hpp"
#include "DynamicDebugHeap.hpp"
#include "List.hpp"
#include "New.hpp"
#include "Sharelock.hpp"
/********************************************************************/ /* */ /* Structures local to the class. */ /* */ /* The structures supplied here describe the layout of the */ /* private per thread heap structures. */ /* */ /********************************************************************/
typedef struct DYNAMIC_HEAP : public LIST { ROCKALL_FRONT_END *Heap; } DYNAMIC_HEAP;
/********************************************************************/ /* */ /* Static data structures. */ /* */ /* The static data structures are initialized and prepared for */ /* use here. */ /* */ /********************************************************************/
STATIC SHARELOCK Sharelock;
/********************************************************************/ /* */ /* Class constructor. */ /* */ /* The overall structure and layout of the heap is controlled */ /* by the various constants and calls made in this function. */ /* There is a significant amount of flexibility available to */ /* a heap which can lead to them having dramatically different */ /* properties. */ /* */ /********************************************************************/
DYNAMIC_DEBUG_HEAP::DYNAMIC_DEBUG_HEAP ( int MaxFreeSpace, bool Recycle, bool SingleImage, bool ThreadSafe, //
// Additional debug flags.
//
bool FunctionTrace, int PercentToDebug, int PercentToPage, bool TrapOnUserError ) : //
// Call the constructors for the contained classes.
//
DebugHeap( 0,false,false,ThreadSafe,FunctionTrace,TrapOnUserError ), FastHeap( MaxFreeSpace,Recycle,false,ThreadSafe ), PageHeap( 0,false,false,ThreadSafe,FunctionTrace,TrapOnUserError ) { //
// Setup various control variables.
//
Active = false;
//
// Create the linked list header and zero
// any other variables.
//
AllHeaps = ((LIST*) SMALL_HEAP::New( sizeof(LIST) )); Array = ((DYNAMIC_HEAP*) SMALL_HEAP::New( (sizeof(DYNAMIC_HEAP) * 3) )); HeapWalk = NULL;
PercentDebug = PercentToDebug; PercentPage = PercentToPage;
//
// We can only activate the the heap if we manage
// to allocate the space we requested.
//
if ( (AllHeaps != NULL) && (Array != NULL)) { //
// Execute the constructors for each linked list
// and for the thread local store.
//
PLACEMENT_NEW( AllHeaps,LIST );
//
// Setup each linked list element.
//
PLACEMENT_NEW( & Array[0],DYNAMIC_HEAP ); PLACEMENT_NEW( & Array[1],DYNAMIC_HEAP ); PLACEMENT_NEW( & Array[2],DYNAMIC_HEAP );
//
// Setup the heap for each linked list
// element and store the pointer.
//
Array[0].Heap = & DebugHeap; Array[1].Heap = & FastHeap; Array[2].Heap = & PageHeap;
//
// Insert each linked list element into
// the list of heaps.
//
Array[0].Insert( AllHeaps ); Array[1].Insert( AllHeaps ); Array[2].Insert( AllHeaps );
//
// Activate the heap.
//
Active = true; } }
/********************************************************************/ /* */ /* Memory deallocation. */ /* */ /* When we delete an allocation we try to each heap in turn */ /* until we find the correct one to use. */ /* */ /********************************************************************/
bool DYNAMIC_DEBUG_HEAP::Delete( void *Address,int Size ) { //
// Although it is very rare there is a chance
// that we failed to build the basic heap structures.
//
if ( Active ) { //
// We try the fastest heap as we are betting
// it is the most common.
//
if ( FastHeap.KnownArea( Address ) ) { return (FastHeap.Delete( Address,Size )); } else { //
// Next we try the debug heap.
//
if ( DebugHeap.KnownArea( Address ) ) { return (DebugHeap.Delete( Address,Size )); } else { //
// Finally we try the page heap.
//
if ( PageHeap.KnownArea( Address ) ) { return (PageHeap.Delete( Address,Size )); } } } }
return false; }
/********************************************************************/ /* */ /* Delete all allocations. */ /* */ /* We walk the list of all the heaps and instruct each heap */ /* to delete everything. */ /* */ /********************************************************************/
void DYNAMIC_DEBUG_HEAP::DeleteAll( bool Recycle ) { //
// Although it is very rare there is a chance
// that we failed to build the basic heap structures.
//
if ( Active ) { REGISTER DYNAMIC_HEAP *Current;
//
// Claim a process wide shared lock
// to ensure the list of heaps does
// not change until we have finished.
//
Sharelock.ClaimShareLock();
//
// You just have to hope the user knows
// what they are doing as everything gets
// blown away.
//
for ( Current = ((DYNAMIC_HEAP*) AllHeaps -> First()); (Current != NULL); Current = ((DYNAMIC_HEAP*) Current -> Next()) ) { Current -> Heap -> DeleteAll( Recycle ); }
//
// Release the lock.
//
Sharelock.ReleaseShareLock(); } }
/********************************************************************/ /* */ /* Memory allocation details. */ /* */ /* When we are asked for details we try to each heap in turn */ /* until we find the correct one to use. */ /* */ /********************************************************************/
bool DYNAMIC_DEBUG_HEAP::Details( void *Address,int *Space ) { return Verify( Address,Space ); }
/********************************************************************/ /* */ /* Print a list of heap leaks. */ /* */ /* We walk the heap and output a list of active heap */ /* allocations to the debug window, */ /* */ /********************************************************************/
void DYNAMIC_DEBUG_HEAP::HeapLeaks( void ) { //
// We call heap leaks for each heap
// that supports the interface.
//
DebugHeap.HeapLeaks(); PageHeap.HeapLeaks(); }
/********************************************************************/ /* */ /* A known area. */ /* */ /* When we are asked about an address we try to each heap in */ /* turn until we find the correct one to use. */ /* */ /********************************************************************/
bool DYNAMIC_DEBUG_HEAP::KnownArea( void *Address ) { //
// Although it is very rare there is a chance
// that we failed to build the basic heap structures.
//
if ( Active ) { //
// We try the fastest heap as we are betting
// it is the most common, followed by the
// degug and the page heaps.
//
return ( FastHeap.KnownArea( Address ) || DebugHeap.KnownArea( Address ) || PageHeap.KnownArea( Address ) ); } else { return false; } }
/********************************************************************/ /* */ /* Claim all the heap locks. */ /* */ /* We claim all of the heap locks so that it is safe to do */ /* operations like walking all of the heaps. */ /* */ /********************************************************************/
void DYNAMIC_DEBUG_HEAP::LockAll( VOID ) { //
// Although it is very rare there is a chance
// that we failed to build the basic heap structures.
//
if ( Active ) { REGISTER DYNAMIC_HEAP *Current;
//
// Claim a process wide shared lock
// to ensure the list of heaps does
// not change until we have finished.
//
Sharelock.ClaimShareLock();
//
// You just have to hope the user knows
// what they are doing as we claim all
// of the heap locks.
//
for ( Current = ((DYNAMIC_HEAP*) AllHeaps -> First()); (Current != NULL); Current = ((DYNAMIC_HEAP*) Current -> Next()) ) { Current -> Heap -> LockAll(); }
//
// Release the lock.
//
Sharelock.ReleaseShareLock(); } }
/********************************************************************/ /* */ /* Multiple memory deallocations. */ /* */ /* When we delete multiple allocations we simply delete each */ /* allocation one at a time. */ /* */ /********************************************************************/
bool DYNAMIC_DEBUG_HEAP::MultipleDelete ( int Actual, void *Array[], int Size ) { REGISTER bool Result = true; REGISTER SBIT32 Count;
//
// We would realy like to use the multiple
// delete functionality of Rockall here but
// it is too much effort. So we simply call
// the standard delete on each entry in the
// array. Although this is not as fast it
// does give more transparent results.
//
for ( Count=0;Count < Actual;Count ++ ) { //
// Delete each memory allocation after
// carefully checking it.
//
if ( ! Delete( Array[ Count ],Size ) ) { Result = false; } }
return Result; }
/********************************************************************/ /* */ /* Multiple memory allocations. */ /* */ /* When we do multiple allocations we simply allocate each */ /* piece of memory one at a time. */ /* */ /********************************************************************/
bool DYNAMIC_DEBUG_HEAP::MultipleNew ( int *Actual, void *Array[], int Requested, int Size, int *Space, bool Zero ) { //
// Although it is very rare there is a chance
// that we failed to build the basic heap structures.
//
if ( Active ) { REGISTER int Random = (RandomNumber() % 100);
//
// We do all the page heap allocations
// in accordance with the supplied ratios.
//
if ( Random <= PercentPage ) { return ( PageHeap.MultipleNew ( Actual, Array, Requested, Size, Space, Zero ) ); } else { //
// Next we do all the debug allocations
// in accordance with the supplied ratios.
//
if ( Random <= (PercentPage + PercentDebug) ) { return ( DebugHeap.MultipleNew ( Actual, Array, Requested, Size, Space, Zero ) ); } else { return ( FastHeap.MultipleNew ( Actual, Array, Requested, Size, Space, Zero ) ); } } } else { (*Actual) = 0;
return false; } }
/********************************************************************/ /* */ /* Memory allocation. */ /* */ /* We allocate from each heap in proportion to the ratios */ /* supplied by the user. */ /* */ /********************************************************************/
void *DYNAMIC_DEBUG_HEAP::New( int Size,int *Space,bool Zero ) { //
// Although it is very rare there is a chance
// that we failed to build the basic heap structures.
//
if ( Active ) { REGISTER int Random = (RandomNumber() % 100);
//
// We do all the page heap allocations
// in accordance with the supplied ratios.
//
if ( Random <= PercentPage ) { return PageHeap.New( Size,Space,Zero ); } else { //
// Next we do all the debug allocations
// in accordance with the supplied ratios.
//
if ( Random <= (PercentPage + PercentDebug) ) { return DebugHeap.New( Size,Space,Zero ); } else { return FastHeap.New( Size,Space,Zero ); } } } else { return NULL; } }
/********************************************************************/ /* */ /* Compute a random number. */ /* */ /* Compute a random number and return it. */ /* */ /********************************************************************/
int DYNAMIC_DEBUG_HEAP::RandomNumber( VOID ) { STATIC int RandomSeed = 1;
//
// Compute a new random seed value.
//
RandomSeed = ( ((RandomSeed >> 32) * 2964557531) + ((RandomSeed & 0xffff) * 2964557531) + 1 );
//
// The new random seed is returned.
//
return (RandomSeed >> 1); }
/********************************************************************/ /* */ /* Memory reallocation. */ /* */ /* We reallocate space for an allocation on the original heap */ /* to make sure this case is well tested. */ /* */ /********************************************************************/
void *DYNAMIC_DEBUG_HEAP::Resize ( void *Address, int NewSize, int Move, int *Space, bool NoDelete, bool Zero ) { //
// Although it is very rare there is a chance
// that we failed to build the basic heap structures.
//
if ( Active ) { //
// We try the fastest heap as we are betting
// it is the most common.
//
if ( FastHeap.KnownArea( Address ) ) { //
// Reallocate the memory as requested.
//
return ( FastHeap.Resize ( Address, NewSize, Move, Space, NoDelete, Zero ) ); } else { //
// Next we try the debug heap.
//
if ( DebugHeap.KnownArea( Address ) ) { //
// Reallocate the memory as requested.
//
return ( DebugHeap.Resize ( Address, NewSize, Move, Space, NoDelete, Zero ) ); } else { //
// Finally we try the page heap.
//
if ( PageHeap.KnownArea( Address ) ) { //
// Reallocate the memory as requested.
//
return ( PageHeap.Resize ( Address, NewSize, Move, Space, NoDelete, Zero ) ); } } } }
return NULL; }
/********************************************************************/ /* */ /* Special memory allocation. */ /* */ /* We sometimes need to allocate some memory from the internal */ /* memory allocator which lives for the lifetime of the heap. */ /* */ /********************************************************************/
void *DYNAMIC_DEBUG_HEAP::SpecialNew( int Size ) { return FastHeap.New( Size ); }
/********************************************************************/ /* */ /* Truncate the heap. */ /* */ /* We need to truncate the heap. This is pretty much a null */ /* call as we do this as we go along anyway. The only thing we */ /* can do is free any space the user suggested keeping earlier. */ /* */ /********************************************************************/
bool DYNAMIC_DEBUG_HEAP::Truncate( int MaxFreeSpace ) { REGISTER bool Result = true;
//
// Although it is very rare there is a chance
// that we failed to build the basic heap structures.
//
if ( Active ) { REGISTER DYNAMIC_HEAP *Current;
//
// Claim a process wide shared lock
// to ensure the list of heaps does
// not change until we have finished.
//
Sharelock.ClaimShareLock();
//
// You just have to hope the user knows
// what they are doing as we are truncating
// all of the heaps.
//
for ( Current = ((DYNAMIC_HEAP*) AllHeaps -> First()); (Current != NULL); Current = ((DYNAMIC_HEAP*) Current -> Next()) ) { //
// If faulty delete is noted during the
// cache flushes then exit with the
// correct status.
//
if ( ! Current -> Heap -> Truncate( MaxFreeSpace ) ) { Result = false; } }
//
// Release the lock.
//
Sharelock.ReleaseShareLock(); }
return Result; }
/********************************************************************/ /* */ /* Release all the heap locks. */ /* */ /* We unlock all of the heap locks so normal processing can */ /* continue on the heaps. */ /* */ /********************************************************************/
void DYNAMIC_DEBUG_HEAP::UnlockAll( VOID ) { //
// Although it is very rare there is a chance
// that we failed to build the basic heap structures.
//
if ( Active ) { REGISTER DYNAMIC_HEAP *Current;
//
// Claim a process wide shared lock
// to ensure the list of heaps does
// not change until we have finished.
//
Sharelock.ClaimShareLock();
//
// You just have to hope the user knows
// what they are doing as we claim all
// of the heap locks.
//
for ( Current = ((DYNAMIC_HEAP*) AllHeaps -> First()); (Current != NULL); Current = ((DYNAMIC_HEAP*) Current -> Next()) ) { Current -> Heap -> UnlockAll(); }
//
// Release the lock.
//
Sharelock.ReleaseShareLock(); } }
/********************************************************************/ /* */ /* Verify a memory allocation details. */ /* */ /* When we verify an allocation we try to each heap in turn */ /* until we find the correct one to use. */ /* */ /********************************************************************/
bool DYNAMIC_DEBUG_HEAP::Verify( void *Address,int *Space ) { //
// Although it is very rare there is a chance
// that we failed to build the basic heap structures.
//
if ( Active ) { //
// We try the fastest heap as we are betting
// it is the most common.
//
if ( FastHeap.KnownArea( Address ) ) { return (FastHeap.Verify( Address,Space )); } else { //
// Next we try the debug heap.
//
if ( DebugHeap.KnownArea( Address ) ) { return (DebugHeap.Verify( Address,Space )); } else { //
// Finally we try the page heap.
//
if ( PageHeap.KnownArea( Address ) ) { return (PageHeap.Verify( Address,Space )); } } } }
return false; }
/********************************************************************/ /* */ /* Walk the heap. */ /* */ /* We have been asked to walk the heap. It is hard to know */ /* why anybody might want to do this given the rest of the */ /* functionality available. Nonetheless, we just do what is */ /* required to keep everyone happy. */ /* */ /********************************************************************/
bool DYNAMIC_DEBUG_HEAP::Walk( bool *Activity,void **Address,int *Space ) { //
// Claim a process wide shared lock
// to ensure the list of heaps does
// not change until we have finished.
//
Sharelock.ClaimShareLock();
//
// Nasty, in 'DYNAMIC_DEBUG_HEAP' we have multiple heaps
// to walk so if we don't have a current heap
// then just select the first available.
//
if ( ((*Address) == NULL) || (HeapWalk == NULL) ) { HeapWalk = ((DYNAMIC_HEAP*) AllHeaps -> First()); }
//
// Walk the heap. When we come to the end of
// the current heap then move on to the next
// heap.
//
while ( (HeapWalk != NULL) && (! HeapWalk -> Heap -> Walk( Activity,Address,Space )) ) { HeapWalk = ((DYNAMIC_HEAP*) HeapWalk -> Next()); }
//
// Release the lock.
//
Sharelock.ReleaseShareLock();
return (HeapWalk != NULL); }
/********************************************************************/ /* */ /* Class destructor. */ /* */ /* Destory the heap. */ /* */ /********************************************************************/
DYNAMIC_DEBUG_HEAP::~DYNAMIC_DEBUG_HEAP( void ) { //
// Although it is very rare there is a chance
// that we failed to build the basic heap structures.
//
if ( Active ) { //
// Deactivate the heap.
//
Active = false;
//
// Delete each linked list element into
// the list of heaps.
//
Array[2].Delete( AllHeaps ); Array[1].Delete( AllHeaps ); Array[0].Delete( AllHeaps );
//
// Delete each linked list element.
//
PLACEMENT_DELETE( & Array[2],DYNAMIC_HEAP ); PLACEMENT_DELETE( & Array[1],DYNAMIC_HEAP ); PLACEMENT_DELETE( & Array[0],DYNAMIC_HEAP );
//
// Call the list and TLS destructors.
//
PLACEMENT_DELETE( AllHeaps,LIST );
//
// Delete the space.
//
SMALL_HEAP::Delete( Array ); SMALL_HEAP::Delete( AllHeaps );
//
// Zero the pointers just to be tidy.
//
HeapWalk = NULL; Array = NULL; AllHeaps = NULL; } }
|