You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1680 lines
48 KiB
1680 lines
48 KiB
// 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 "Cache.hpp"
|
|
#include "Common.hpp"
|
|
#include "Find.hpp"
|
|
#include "Heap.hpp"
|
|
#include "New.hpp"
|
|
#include "NewPage.hpp"
|
|
#include "Rockall.hpp"
|
|
#include "Spinlock.hpp"
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Constants local to the class. */
|
|
/* */
|
|
/* The constants supplied here try to make the layout of the */
|
|
/* the caches easier to understand and update. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
CONST SBIT32 EnableLookAside = 0;
|
|
CONST SBIT32 GlobalMask = (sizeof(SBIT64) - 1);
|
|
CONST SBIT32 GlobalPaddedSize = (sizeof(FIND) + GlobalMask);
|
|
CONST SBIT32 GlobalByteSize = (GlobalPaddedSize & ~GlobalMask);
|
|
CONST SBIT32 GlobalWordSize = (GlobalByteSize / sizeof(SBIT64));
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Static member initialization. */
|
|
/* */
|
|
/* Static member initialization sets the initial value for all */
|
|
/* static members. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
STATIC SBIT64 GlobalFind[ GlobalWordSize ];
|
|
STATIC SBIT32 ReferenceCount = 0;
|
|
STATIC SPINLOCK Spinlock;
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Class constructor. */
|
|
/* */
|
|
/* The interface default constructor creates a null heap for */
|
|
/* internal use by selected classes. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
ROCKALL::ROCKALL( void )
|
|
{
|
|
//
|
|
// A heap constructed by this constructor should
|
|
// never be used. Hence, we zero key pointers to
|
|
// ensure grave disorder will result if anyone tries.
|
|
//
|
|
Array = NULL;
|
|
Caches = NULL;
|
|
Find = NULL;
|
|
Heap = NULL;
|
|
NewPage = NULL;
|
|
|
|
GlobalDelete = True;
|
|
GuardWord = GuardValue;
|
|
NumberOfCaches = 0;
|
|
TotalSize = 0;
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* 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 within heaps */
|
|
/* leading to potentially dramatically different properties. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
ROCKALL::ROCKALL
|
|
(
|
|
CACHE_DETAILS *Caches1,
|
|
CACHE_DETAILS *Caches2,
|
|
int FindCacheSize,
|
|
int FindCacheThreshold,
|
|
int FindSize,
|
|
int MaxFreeSpace,
|
|
int *NewPageSizes,
|
|
bool Recycle,
|
|
bool SingleImage,
|
|
int Stride1,
|
|
int Stride2,
|
|
bool ThreadSafe
|
|
)
|
|
{
|
|
#ifdef DISABLE_STRUCTURED_EXCEPTIONS
|
|
TRY
|
|
#endif
|
|
{
|
|
REGISTER int AlignMask = ((int) (NaturalSize()-1));
|
|
REGISTER int Stride = (sizeof(CACHE_DETAILS));
|
|
REGISTER int Size1 = (ComputeSize( ((char*) Caches1),Stride ));
|
|
REGISTER int Size2 = (ComputeSize( ((char*) Caches2),Stride ));
|
|
REGISTER int Size3 = (ComputeSize( ((char*) NewPageSizes),sizeof(int) ));
|
|
|
|
//
|
|
// The interface pointer members are zeroed to
|
|
// ensure they do not end up containing random
|
|
// rubbish whatever happens.
|
|
//
|
|
Array = NULL;
|
|
Caches = NULL;
|
|
Find = NULL;
|
|
Heap = NULL;
|
|
NewPage = NULL;
|
|
|
|
//
|
|
// Set key flags and compute information about
|
|
// the number of caches and the total amount of
|
|
// space required for the low level heap structures.
|
|
//
|
|
GlobalDelete = SingleImage;
|
|
GuardWord = GuardValue;
|
|
NumberOfCaches = (Size1 + Size2);
|
|
|
|
TotalSize =
|
|
(
|
|
(NumberOfCaches * sizeof(CACHE*))
|
|
+
|
|
(NumberOfCaches * sizeof(CACHE))
|
|
+
|
|
((GlobalDelete) ? 0 : sizeof(FIND))
|
|
+
|
|
(sizeof(NEW_PAGE))
|
|
+
|
|
(sizeof(HEAP))
|
|
);
|
|
|
|
//
|
|
// Ensure the alignment mask is valid and we have
|
|
// at least four caches. If not the heap will be
|
|
// worthless.
|
|
//
|
|
if
|
|
(
|
|
(COMMON::PowerOfTwo( ((SBIT32) (AlignMask+1)) ))
|
|
&&
|
|
((Size1 >= 1) && (Size2 >= 3))
|
|
&&
|
|
((Stride1 > 0) && (COMMON::PowerOfTwo( Stride1 )))
|
|
&&
|
|
((Stride2 >= Stride1) && (COMMON::PowerOfTwo( Stride2 )))
|
|
)
|
|
{
|
|
REGISTER CHAR *NewMemory =
|
|
((CHAR*) NewArea( ((SBIT32) AlignMask),TotalSize,False ));
|
|
|
|
//
|
|
// We check to make sure that we can allocate space
|
|
// to store the low level heap control information.
|
|
// If not we exit.
|
|
//
|
|
if ( NewMemory != NULL )
|
|
{
|
|
REGISTER SBIT32 Count;
|
|
|
|
//
|
|
// Build the caches.
|
|
//
|
|
// The first step in creating a heap is to
|
|
// create all the caches and related buckets
|
|
// requested by the user.
|
|
//
|
|
Caches = ((CACHE*) NewMemory);
|
|
NewMemory += (NumberOfCaches * sizeof(CACHE));
|
|
|
|
for ( Count=0;Count < Size1;Count ++ )
|
|
{
|
|
REGISTER CACHE_DETAILS *Current = & Caches1[ Count ];
|
|
|
|
PLACEMENT_NEW( & Caches[ Count ],CACHE )
|
|
(
|
|
((SBIT32) Current -> AllocationSize),
|
|
((SBIT32) Current -> CacheSize),
|
|
((SBIT32) Current -> ChunkSize),
|
|
((SBIT32) Current -> PageSize),
|
|
((BOOLEAN) Recycle),
|
|
((BOOLEAN) ThreadSafe)
|
|
);
|
|
}
|
|
|
|
for ( Count=0;Count < Size2;Count ++ )
|
|
{
|
|
REGISTER CACHE_DETAILS *Current = & Caches2[ Count ];
|
|
|
|
PLACEMENT_NEW( & Caches[ (Count + Size1) ],CACHE )
|
|
(
|
|
((SBIT32) Current -> AllocationSize),
|
|
((SBIT32) Current -> CacheSize),
|
|
((SBIT32) Current -> ChunkSize),
|
|
((SBIT32) Current -> PageSize),
|
|
((BOOLEAN) Recycle),
|
|
((BOOLEAN) ThreadSafe)
|
|
);
|
|
}
|
|
|
|
//
|
|
// Build the cache array.
|
|
//
|
|
// After we have constructed all of the caches
|
|
// we take the address of each cache and load
|
|
// it into an array. This indirection allows
|
|
// caches to be shared between heaps.
|
|
//
|
|
Array = (CACHE**) NewMemory;
|
|
NewMemory += (NumberOfCaches * sizeof(CACHE*));
|
|
|
|
for ( Count=0;Count < NumberOfCaches;Count ++ )
|
|
{ Array[ Count ] = & Caches[ Count ]; }
|
|
|
|
//
|
|
// Configuration of the find hash table.
|
|
//
|
|
// The find hash table maps addresses to page
|
|
// descriptions and is a key part of the memory
|
|
// deallocation mechanism. Here we specify
|
|
// the size of the hash table. It is important
|
|
// to size it based on the expected number of
|
|
// memory allocations. Nonetheless, it will
|
|
// automatically grow if the correct option is
|
|
// set and it is clearly too small.
|
|
//
|
|
if ( GlobalDelete )
|
|
{
|
|
//
|
|
// We claim a lock just in case there
|
|
// are multiple threads.
|
|
//
|
|
Spinlock.ClaimLock();
|
|
|
|
//
|
|
// We create the global find hash table
|
|
// if we are the first thread to create
|
|
// a heap.
|
|
//
|
|
if ( (ReferenceCount ++) == 0 )
|
|
{
|
|
STATIC ROCKALL Rockall;
|
|
|
|
//
|
|
// Select the global find table
|
|
// and call the constructor.
|
|
//
|
|
Find = ((FIND*) GlobalFind);
|
|
|
|
PLACEMENT_NEW( Find,FIND )
|
|
(
|
|
((SBIT32) FindSize),
|
|
((SBIT32) FindCacheSize),
|
|
((SBIT32) EnableLookAside),
|
|
((ROCKALL*) & Rockall),
|
|
((BOOLEAN) True),
|
|
((BOOLEAN) (GlobalDelete || ThreadSafe))
|
|
);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// A global find has table already
|
|
// exists so just use it.
|
|
//
|
|
Find = ((FIND*) GlobalFind);
|
|
}
|
|
|
|
//
|
|
// Release the lock now.
|
|
//
|
|
Spinlock.ReleaseLock();
|
|
}
|
|
else
|
|
{
|
|
Find = (FIND*) NewMemory;
|
|
NewMemory += sizeof(FIND);
|
|
|
|
//
|
|
// We create a local find hash table
|
|
// if we are do not need to provide
|
|
// a single heap image.
|
|
//
|
|
PLACEMENT_NEW( Find,FIND )
|
|
(
|
|
((SBIT32) FindSize),
|
|
((SBIT32) FindCacheSize),
|
|
((SBIT32) FindCacheThreshold),
|
|
((ROCKALL*) this),
|
|
((BOOLEAN) True),
|
|
((BOOLEAN) ThreadSafe)
|
|
);
|
|
}
|
|
|
|
//
|
|
// Configuration of the allocation overhead.
|
|
//
|
|
// The allocation overhead is controlled by
|
|
// the size of the bit vectors used to keep
|
|
// track of the allocations. There is a built
|
|
// in limit of ((2^15)-1) elements in a single
|
|
// bit vector.
|
|
//
|
|
NewPage = (NEW_PAGE*) NewMemory;
|
|
NewMemory += sizeof(NEW_PAGE);
|
|
|
|
PLACEMENT_NEW( NewPage,NEW_PAGE )
|
|
(
|
|
((FIND*) Find),
|
|
((SBIT32*) NewPageSizes),
|
|
((ROCKALL*) this),
|
|
((SBIT32) Size3),
|
|
((BOOLEAN) ThreadSafe)
|
|
);
|
|
|
|
//
|
|
// Create the heap.
|
|
//
|
|
// We can now create the heap. We do this
|
|
// by passing pointers to all the parts of
|
|
// the heap that we have just created.
|
|
//
|
|
//
|
|
Heap = (HEAP*) NewMemory;
|
|
|
|
PLACEMENT_NEW( Heap,HEAP )
|
|
(
|
|
((CACHE**) & Array[0]),
|
|
((CACHE**) & Array[ Size1 ]),
|
|
((SBIT32) MaxFreeSpace),
|
|
((FIND*) Find),
|
|
((NEW_PAGE*) NewPage),
|
|
((ROCKALL*) this),
|
|
((SBIT32) Size1),
|
|
((SBIT32) Size2),
|
|
((SBIT32) Stride1),
|
|
((SBIT32) Stride2),
|
|
ThreadSafe
|
|
);
|
|
}
|
|
else
|
|
{ Failure( "Heap constructor failed in ROCKALL" ); }
|
|
}
|
|
else
|
|
{ Failure( "Cache size in constructor for ROCKALL" ); }
|
|
}
|
|
#ifdef DISABLE_STRUCTURED_EXCEPTIONS
|
|
#ifdef DEBUGGING
|
|
catch ( FAULT Message )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable, print a
|
|
// suitable message and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
|
|
DebugPrint( "Exception caught: %s\n",(char*) Message );
|
|
}
|
|
#endif
|
|
catch ( ... )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Compute the size of the caches. */
|
|
/* */
|
|
/* Compute the size of various data structures for internal */
|
|
/* sizing purposes. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
int ROCKALL::ComputeSize( char *Array,int Stride )
|
|
{
|
|
register int Count;
|
|
|
|
for
|
|
(
|
|
Count=0;
|
|
((*((int*) & Array[ Count ])) != 0);
|
|
Count += Stride
|
|
);
|
|
|
|
return (Count / Stride);
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Memory deallocation. */
|
|
/* */
|
|
/* Lets start with some basic tests. If the address we have */
|
|
/* been given is special, clearly wrong or the heap has not */
|
|
/* been initialized then we fail and exit. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
bool ROCKALL::Delete( void *Address,int Size )
|
|
{
|
|
TRY
|
|
{
|
|
//
|
|
// We verify that the parameters look
|
|
// reasonable and the heap is not corrupt
|
|
// and then try to delete the supplied
|
|
// allocation.
|
|
//
|
|
if ( Available() )
|
|
{ return (Heap -> Delete( ((VOID*) Address),((SBIT32) Size) )); }
|
|
}
|
|
#ifdef DISABLE_STRUCTURED_EXCEPTIONS
|
|
#ifdef DEBUGGING
|
|
catch ( FAULT Message )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable, print a
|
|
// suitable message and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
|
|
DebugPrint( "Exception caught: %s\n",(char*) Message );
|
|
}
|
|
#endif
|
|
catch ( ... )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
}
|
|
#else
|
|
__except ( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
}
|
|
#endif
|
|
|
|
return false;
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Delete all allocations. */
|
|
/* */
|
|
/* At certain places in am application we sometimes need to */
|
|
/* delete a significant number of allocations. If all of */
|
|
/* these allocations are placed into a single heap we can */
|
|
/* delete them all using this call. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
void ROCKALL::DeleteAll( bool Recycle )
|
|
{
|
|
TRY
|
|
{
|
|
//
|
|
// The call appears to be valid so if the
|
|
// heap is not corrupt then pass it along
|
|
// for processing.
|
|
//
|
|
if ( Available() )
|
|
{ Heap -> DeleteAll( (BOOLEAN) Recycle ); }
|
|
}
|
|
#ifdef DISABLE_STRUCTURED_EXCEPTIONS
|
|
#ifdef DEBUGGING
|
|
catch ( FAULT Message )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable, print a
|
|
// suitable message and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
|
|
DebugPrint( "Exception caught: %s\n",(char*) Message );
|
|
}
|
|
#endif
|
|
catch ( ... )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
}
|
|
#else
|
|
__except ( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Delete allocation area. */
|
|
/* */
|
|
/* All memory requests are eventually sent back to the external */
|
|
/* deallocator. This function can be overloaded so that memory */
|
|
/* can be provided from any source. The default is to send */
|
|
/* the area back to the operating system. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
void ROCKALL::DeleteArea( void *Memory,int Size,bool User )
|
|
{
|
|
REGISTER DWORD NewSize = ((Size == 0) ? Size : 0);
|
|
|
|
#ifdef DEBUGGING
|
|
#ifdef ENABLE_ALLOCATION_STATISTICS
|
|
//
|
|
// When we are debugging print out trace information.
|
|
//
|
|
DebugPrint( "Delete\t 0x%08x %d bytes\n",Memory,Size );
|
|
|
|
#endif
|
|
#endif
|
|
//
|
|
// The NT 'VirtualFree' call requires the 'Size'
|
|
// to be zero. This may not be true of all
|
|
// deallocators so we pass the value and then
|
|
// replace it with zero above.
|
|
//
|
|
if ( VirtualFree( Memory,NewSize,MEM_RELEASE ) == NULL )
|
|
{ Failure( "Delete fails in DeleteArea" ); }
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Memory allocation details. */
|
|
/* */
|
|
/* Lets start with some basic tests. If the address we have */
|
|
/* been given is special, clearly wrong or the heap has not */
|
|
/* been initialized then we fail the call appropriately. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
bool ROCKALL::Details( void *Address,int *Space )
|
|
{
|
|
TRY
|
|
{
|
|
//
|
|
// The call appears to be valid so if the
|
|
// heap is not corrupt then pass it along
|
|
// for processing.
|
|
//
|
|
if ( Available() )
|
|
{ return (Heap -> Details( ((VOID*) Address),((SBIT32*) Space) )); }
|
|
}
|
|
#ifdef DISABLE_STRUCTURED_EXCEPTIONS
|
|
#ifdef DEBUGGING
|
|
catch ( FAULT Message )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable, print a
|
|
// suitable message and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
|
|
DebugPrint( "Exception caught: %s\n",(char*) Message );
|
|
}
|
|
#endif
|
|
catch ( ... )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
}
|
|
#else
|
|
__except ( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
}
|
|
#endif
|
|
|
|
return false;
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* A known area. */
|
|
/* */
|
|
/* We have an address and don't have a clue which heap */
|
|
/* owns the space. Here we take a look at the address */
|
|
/* and figure out it it belongs to the current heap. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
bool ROCKALL::KnownArea( void *Address )
|
|
{
|
|
TRY
|
|
{
|
|
//
|
|
// The call appears to be valid so if the
|
|
// heap is not corrupt then pass it along
|
|
// for processing.
|
|
//
|
|
if ( Available() )
|
|
{
|
|
return ( Heap -> KnownArea( ((VOID*) Address) ) );
|
|
}
|
|
}
|
|
#ifdef DISABLE_STRUCTURED_EXCEPTIONS
|
|
#ifdef DEBUGGING
|
|
catch ( FAULT Message )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable, print a
|
|
// suitable message and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
|
|
DebugPrint( "Exception caught: %s\n",(char*) Message );
|
|
}
|
|
#endif
|
|
catch ( ... )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
}
|
|
#else
|
|
__except ( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
}
|
|
#endif
|
|
|
|
return false;
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Claim all the heap locks. */
|
|
/* */
|
|
/* Lets start with some basic tests. If the address we have */
|
|
/* been given is special, clearly wrong or the heap has not */
|
|
/* been initialized then we fail and exit. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
void ROCKALL::LockAll( VOID )
|
|
{
|
|
TRY
|
|
{
|
|
//
|
|
// The call appears to be valid so if the
|
|
// heap is not corrupt then pass it along
|
|
// for processing.
|
|
//
|
|
if ( Available() )
|
|
{ Heap -> LockAll(); }
|
|
}
|
|
#ifdef DISABLE_STRUCTURED_EXCEPTIONS
|
|
#ifdef DEBUGGING
|
|
catch ( FAULT Message )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable, print a
|
|
// suitable message and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
|
|
DebugPrint( "Exception caught: %s\n",(char*) Message );
|
|
}
|
|
#endif
|
|
catch ( ... )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
}
|
|
#else
|
|
__except ( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Multiple memory deallocations. */
|
|
/* */
|
|
/* Lets start with some basic tests. If the address we have */
|
|
/* been given is special, clearly wrong or the heap has not */
|
|
/* been initialized then we fail and exit. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
bool ROCKALL::MultipleDelete
|
|
(
|
|
int Actual,
|
|
void *Array[],
|
|
int Size
|
|
)
|
|
{
|
|
TRY
|
|
{
|
|
//
|
|
// We verify that the parameters look
|
|
// reasonable and the heap is not corrupt
|
|
// and then try to delete the supplied
|
|
// allocations.
|
|
//
|
|
if ( (Actual > 0) && (Array != NULL) && (Available()) )
|
|
{
|
|
return
|
|
(
|
|
Heap -> MultipleDelete
|
|
(
|
|
((SBIT32) Actual),
|
|
((VOID**) Array),
|
|
((SBIT32) Size)
|
|
)
|
|
);
|
|
}
|
|
}
|
|
#ifdef DISABLE_STRUCTURED_EXCEPTIONS
|
|
#ifdef DEBUGGING
|
|
catch ( FAULT Message )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable, print a
|
|
// suitable message and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
|
|
DebugPrint( "Exception caught: %s\n",(char*) Message );
|
|
}
|
|
#endif
|
|
catch ( ... )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
}
|
|
#else
|
|
__except ( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
}
|
|
#endif
|
|
|
|
return false;
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Multiple memory allocations. */
|
|
/* */
|
|
/* Lets start with some basic tests. If the address we have */
|
|
/* been given is special, clearly wrong or the heap has not */
|
|
/* been initialized then we fail and exit. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
bool ROCKALL::MultipleNew
|
|
(
|
|
int *Actual,
|
|
void *Array[],
|
|
int Requested,
|
|
int Size,
|
|
int *Space,
|
|
bool Zero
|
|
)
|
|
{
|
|
TRY
|
|
{
|
|
//
|
|
// We verify that the parameters look
|
|
// reasonable and the heap is not corrupt
|
|
// and then try to create the requested
|
|
// allocation.
|
|
//
|
|
if
|
|
(
|
|
((Array != NULL) && (Available()))
|
|
&&
|
|
((Requested > 0) && (Size >= 0))
|
|
)
|
|
{
|
|
return
|
|
(
|
|
Heap -> MultipleNew
|
|
(
|
|
((SBIT32*) Actual),
|
|
((VOID**) Array),
|
|
((SBIT32) Requested),
|
|
((SBIT32) ((Size > 0) ? Size : 1)),
|
|
((SBIT32*) Space),
|
|
((BOOLEAN) Zero)
|
|
)
|
|
);
|
|
}
|
|
}
|
|
#ifdef DISABLE_STRUCTURED_EXCEPTIONS
|
|
#ifdef DEBUGGING
|
|
catch ( FAULT Message )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable, print a
|
|
// suitable message and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
|
|
DebugPrint( "Exception caught: %s\n",(char*) Message );
|
|
}
|
|
#endif
|
|
catch ( ... )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
}
|
|
#else
|
|
__except ( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
}
|
|
#endif
|
|
|
|
return false;
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* The natural allocation size. */
|
|
/* */
|
|
/* We would like to know a good default size for allocations. */
|
|
/* The default is to ask the operating system for the */
|
|
/* allocation granularity. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
int ROCKALL::NaturalSize( void )
|
|
{
|
|
STATIC SBIT32 AllocationSize = 0;
|
|
|
|
//
|
|
// Ask the operation system for the allocation
|
|
// granularity.
|
|
//
|
|
if ( AllocationSize <= 0 )
|
|
{
|
|
AUTO SYSTEM_INFO SystemInformation;
|
|
|
|
GetSystemInfo( & SystemInformation );
|
|
|
|
AllocationSize = (SBIT32) SystemInformation.dwAllocationGranularity;
|
|
}
|
|
|
|
return ((int) AllocationSize);
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Memory allocation. */
|
|
/* */
|
|
/* Lets start with some basic tests. If the address we have */
|
|
/* been given is special, clearly wrong or the heap has not */
|
|
/* been initialized then we fail and exit. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
void *ROCKALL::New( int Size,int *Space,bool Zero )
|
|
{
|
|
TRY
|
|
{
|
|
//
|
|
// We verify that the parameters look
|
|
// reasonable and the heap is not corrupt
|
|
// and then try to create the requested
|
|
// allocation.
|
|
//
|
|
if ( (Available()) && (Size >= 0) )
|
|
{
|
|
return
|
|
(
|
|
Heap -> New
|
|
(
|
|
((SBIT32) ((Size > 0) ? Size : 1)),
|
|
((SBIT32*) Space),
|
|
((BOOLEAN) Zero)
|
|
)
|
|
);
|
|
}
|
|
}
|
|
#ifdef DISABLE_STRUCTURED_EXCEPTIONS
|
|
#ifdef DEBUGGING
|
|
catch ( FAULT Message )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable, print a
|
|
// suitable message and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
|
|
DebugPrint( "Exception caught: %s\n",(char*) Message );
|
|
}
|
|
#endif
|
|
catch ( ... )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
}
|
|
#else
|
|
__except ( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
}
|
|
#endif
|
|
|
|
return ((void*) AllocationFailure);
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* New allocation area. */
|
|
/* */
|
|
/* All memory requests are eventually sent to the new external */
|
|
/* allocator. This function can be overloaded so that memory */
|
|
/* can be provided from any source. The default is to get */
|
|
/* new memory from the operating system. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
void *ROCKALL::NewArea( int AlignMask,int Size,bool User )
|
|
{
|
|
//
|
|
// When there is an alignment requirement greater
|
|
// than the natural alignment provided by the
|
|
// operating system we have to play various tricks
|
|
// to allocate a suitable block. If not then we
|
|
// just do a normal allocation call.
|
|
//
|
|
if ( AlignMask > NaturalSize() )
|
|
{
|
|
REGISTER SBIT32 NewSize = (AlignMask + Size);
|
|
|
|
//
|
|
// We need to allocate a block with an
|
|
// alignment requirement greater than
|
|
// the operating system default. So we
|
|
// allocate a much larger block and
|
|
// release the parts we don't need.
|
|
//
|
|
while ( True )
|
|
{
|
|
REGISTER VOID *Reserved =
|
|
(
|
|
VirtualAlloc
|
|
(
|
|
NULL,
|
|
((DWORD) NewSize),
|
|
MEM_RESERVE,
|
|
PAGE_READWRITE
|
|
)
|
|
);
|
|
|
|
//
|
|
// Lets ensure we were able to find a suitable
|
|
// memory block. If not then we exit.
|
|
//
|
|
if ( Reserved != NULL )
|
|
{
|
|
//
|
|
// We just want to return the parts of
|
|
// the block we don't need but 'NT' is
|
|
// not smart enough. So we free the
|
|
// entire block.
|
|
//
|
|
if ( VirtualFree( Reserved,0,MEM_RELEASE ) )
|
|
{
|
|
REGISTER LONG Address = ((LONG) Reserved);
|
|
REGISTER VOID *NewMemory;
|
|
|
|
//
|
|
// Compute the base address of the part
|
|
// of the block we really want to allocate.
|
|
//
|
|
Address = ((Address + AlignMask) & ~AlignMask);
|
|
|
|
//
|
|
// Finally, lets reallocate the part of
|
|
// the block we wanted but just released
|
|
// and hope that nobody else got it before
|
|
// us.
|
|
//
|
|
NewMemory =
|
|
(
|
|
VirtualAlloc
|
|
(
|
|
((LPVOID) Address),
|
|
((DWORD) Size),
|
|
(MEM_RESERVE | MEM_COMMIT),
|
|
PAGE_READWRITE
|
|
)
|
|
);
|
|
|
|
//
|
|
// If it all worked we can exit.
|
|
//
|
|
if ( NewMemory != NULL )
|
|
{
|
|
#ifdef DEBUGGING
|
|
#ifdef ENABLE_ALLOCATION_STATISTICS
|
|
//
|
|
// When we are debugging output
|
|
// out trace information.
|
|
//
|
|
DebugPrint
|
|
(
|
|
"New\t\t 0x%08x %d bytes\n",
|
|
NewMemory,
|
|
Size
|
|
);
|
|
|
|
#endif
|
|
#endif
|
|
return ((void*) NewMemory);
|
|
}
|
|
}
|
|
else
|
|
{ return ((void*) AllocationFailure); }
|
|
|
|
}
|
|
else
|
|
{ return ((void*) AllocationFailure); }
|
|
}
|
|
}
|
|
else
|
|
{
|
|
REGISTER VOID *NewMemory;
|
|
|
|
//
|
|
// We can allocate directly from the operating
|
|
// system as the default alignment requirement
|
|
// is enough for this case.
|
|
//
|
|
NewMemory =
|
|
(
|
|
VirtualAlloc
|
|
(
|
|
NULL,
|
|
((DWORD) Size),
|
|
MEM_COMMIT,
|
|
PAGE_READWRITE
|
|
)
|
|
);
|
|
#ifdef DEBUGGING
|
|
#ifdef ENABLE_ALLOCATION_STATISTICS
|
|
|
|
if ( NewMemory != NULL )
|
|
{
|
|
//
|
|
// When we are debugging output out trace
|
|
// information.
|
|
//
|
|
DebugPrint( "New\t\t 0x%08x %d bytes\n",NewMemory,Size );
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
return ((void*) NewMemory);
|
|
}
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Memory reallocation. */
|
|
/* */
|
|
/* Lets start with some basic tests. If the address we have */
|
|
/* been given is special, clearly wrong or the heap has not */
|
|
/* been initialized then we fail and exit. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
void *ROCKALL::Resize
|
|
(
|
|
void *Address,
|
|
int NewSize,
|
|
int Move,
|
|
int *Space,
|
|
bool NoDelete,
|
|
bool Zero
|
|
)
|
|
{
|
|
TRY
|
|
{
|
|
//
|
|
// A well known practice is to try to
|
|
// resize a null pointer. This is really
|
|
// a very poor style but we support it
|
|
// in any case.
|
|
//
|
|
if ( Address != ((void*) AllocationFailure) )
|
|
{
|
|
//
|
|
// We verify that the parameters look
|
|
// reasonable and the heap is not corrupt
|
|
// and then try to resize the supplied
|
|
// allocation.
|
|
//
|
|
if ( (Available()) && (NewSize >= 0) )
|
|
{
|
|
return
|
|
(
|
|
Heap -> Resize
|
|
(
|
|
((VOID*) Address),
|
|
((SBIT32) ((NewSize > 0) ? NewSize : 1)),
|
|
((SBIT32) Move),
|
|
((SBIT32*) Space),
|
|
((BOOLEAN) NoDelete),
|
|
((BOOLEAN) Zero)
|
|
)
|
|
);
|
|
}
|
|
}
|
|
else
|
|
{ return (New( NewSize,Space,Zero )); }
|
|
}
|
|
#ifdef DISABLE_STRUCTURED_EXCEPTIONS
|
|
#ifdef DEBUGGING
|
|
catch ( FAULT Message )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable, print a
|
|
// suitable message and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
|
|
DebugPrint( "Exception caught: %s\n",(char*) Message );
|
|
}
|
|
#endif
|
|
catch ( ... )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
}
|
|
#else
|
|
__except ( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
}
|
|
#endif
|
|
|
|
return ((void*) AllocationFailure);
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Special memory allocation. */
|
|
/* */
|
|
/* We sometimes need to allocate some memory from the internal */
|
|
/* memory allocator which lives for the lifetime of the heap. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
void *ROCKALL::SpecialNew( int Size )
|
|
{
|
|
TRY
|
|
{
|
|
//
|
|
// We verify that the parameters look
|
|
// reasonable and the heap is not corrupt
|
|
// and then try to create the requested
|
|
// allocation.
|
|
//
|
|
if ( (Available()) && (Size > 0) )
|
|
{ return (Heap -> SpecialNew( ((SBIT32) Size) )); }
|
|
}
|
|
#ifdef DISABLE_STRUCTURED_EXCEPTIONS
|
|
#ifdef DEBUGGING
|
|
catch ( FAULT Message )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable, print a
|
|
// suitable message and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
|
|
DebugPrint( "Exception caught: %s\n",(char*) Message );
|
|
}
|
|
#endif
|
|
catch ( ... )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
}
|
|
#else
|
|
__except ( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
}
|
|
#endif
|
|
|
|
return ((void*) AllocationFailure);
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* 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 ROCKALL::Truncate( int MaxFreeSpace )
|
|
{
|
|
TRY
|
|
{
|
|
//
|
|
// The call appears to be valid so if the
|
|
// heap is not corrupt then pass it along
|
|
// for processing.
|
|
//
|
|
if ( Available() )
|
|
{ return (Heap -> Truncate( (SBIT32) MaxFreeSpace )); }
|
|
}
|
|
#ifdef DISABLE_STRUCTURED_EXCEPTIONS
|
|
#ifdef DEBUGGING
|
|
catch ( FAULT Message )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable, print a
|
|
// suitable message and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
|
|
DebugPrint( "Exception caught: %s\n",(char*) Message );
|
|
}
|
|
#endif
|
|
catch ( ... )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
}
|
|
#else
|
|
__except ( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
}
|
|
#endif
|
|
|
|
return false;
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Release all the heap locks. */
|
|
/* */
|
|
/* Lets start with some basic tests. If the address we have */
|
|
/* been given is special, clearly wrong or the heap has not */
|
|
/* been initialized then we fail and exit. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
void ROCKALL::UnlockAll( VOID )
|
|
{
|
|
TRY
|
|
{
|
|
//
|
|
// The call appears to be valid so if the
|
|
// heap is not corrupt then pass it along
|
|
// for processing.
|
|
//
|
|
if ( Available() )
|
|
{ Heap -> UnlockAll(); }
|
|
}
|
|
#ifdef DISABLE_STRUCTURED_EXCEPTIONS
|
|
#ifdef DEBUGGING
|
|
catch ( FAULT Message )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable, print a
|
|
// suitable message and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
|
|
DebugPrint( "Exception caught: %s\n",(char*) Message );
|
|
}
|
|
#endif
|
|
catch ( ... )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
}
|
|
#else
|
|
__except ( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Verify a memory allocation details. */
|
|
/* */
|
|
/* Lets start with some basic tests. If the address we have */
|
|
/* been given is special, clearly wrong or the heap has not */
|
|
/* been initialized then we fail the call appropriately. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
bool ROCKALL::Verify( void *Address,int *Space )
|
|
{
|
|
TRY
|
|
{
|
|
//
|
|
// The call appears to be valid so if the
|
|
// heap is not corrupt then pass it along
|
|
// for processing.
|
|
//
|
|
if ( Available() )
|
|
{
|
|
return
|
|
(
|
|
(Address == ((void*) AllocationFailure))
|
|
||
|
|
(Heap -> Verify( ((VOID*) Address),((SBIT32*) Space) ))
|
|
);
|
|
}
|
|
}
|
|
#ifdef DISABLE_STRUCTURED_EXCEPTIONS
|
|
#ifdef DEBUGGING
|
|
catch ( FAULT Message )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable, print a
|
|
// suitable message and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
|
|
DebugPrint( "Exception caught: %s\n",(char*) Message );
|
|
}
|
|
#endif
|
|
catch ( ... )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
}
|
|
#else
|
|
__except ( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
}
|
|
#endif
|
|
|
|
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 ROCKALL::Walk( bool *Active,void **Address,int *Space )
|
|
{
|
|
TRY
|
|
{
|
|
|
|
//
|
|
// The call appears to be valid so if the
|
|
// heap is not corrupt then pass it along
|
|
// for processing.
|
|
//
|
|
if ( Available() )
|
|
{
|
|
AUTO BOOLEAN NewActive;
|
|
|
|
//
|
|
// Walk the active heap.
|
|
//
|
|
if
|
|
(
|
|
Heap -> Walk
|
|
(
|
|
((BOOLEAN*) & NewActive),
|
|
((VOID**) Address),
|
|
((SBIT32*) Space)
|
|
)
|
|
)
|
|
{
|
|
(*Active) = (NewActive != False);
|
|
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
#ifdef DISABLE_STRUCTURED_EXCEPTIONS
|
|
#ifdef DEBUGGING
|
|
catch ( FAULT Message )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable, print a
|
|
// suitable message and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
|
|
DebugPrint( "Exception caught: %s\n",(char*) Message );
|
|
}
|
|
#endif
|
|
catch ( ... )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
}
|
|
#else
|
|
__except ( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
}
|
|
#endif
|
|
|
|
return false;
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Class destructor. */
|
|
/* */
|
|
/* Destory the current heap. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
ROCKALL::~ROCKALL( void )
|
|
{
|
|
TRY
|
|
{
|
|
//
|
|
// We are about to destroy a heap but before we
|
|
// start we make sure that the heap is not corrupt
|
|
// and seems to be in reasonable shape. If not we
|
|
// leave it alone to avoid possible trouble.
|
|
//
|
|
if ( (Available()) && (NumberOfCaches > 0) && (TotalSize > 0) )
|
|
{
|
|
REGISTER SBIT32 Count;
|
|
|
|
//
|
|
// Execute the heap destructor.
|
|
//
|
|
PLACEMENT_DELETE( Heap,HEAP );
|
|
|
|
//
|
|
// Execute the new page destructor.
|
|
//
|
|
PLACEMENT_DELETE( NewPage,NEW_PAGE );
|
|
|
|
//
|
|
// Execute the find hash table destructor.
|
|
//
|
|
if ( GlobalDelete )
|
|
{
|
|
//
|
|
// We only delete the global find hash
|
|
// table if the reference count is zero.
|
|
//
|
|
Spinlock.ClaimLock();
|
|
|
|
if ( (-- ReferenceCount) == 0 )
|
|
{ PLACEMENT_DELETE( Find,FIND ); }
|
|
|
|
Spinlock.ReleaseLock();
|
|
}
|
|
else
|
|
{ PLACEMENT_DELETE( Find,FIND ); }
|
|
|
|
|
|
//
|
|
// Execute the cache destructors.
|
|
//
|
|
for ( Count=0;Count < NumberOfCaches;Count ++ )
|
|
{ PLACEMENT_DELETE( & Caches[ Count ],CACHE ); }
|
|
|
|
//
|
|
// Deallocate the heap structures.
|
|
//
|
|
DeleteArea( ((VOID*) Caches),TotalSize,False );
|
|
|
|
//
|
|
// Finally, zero any remaining members.
|
|
// We really do not need to do this but
|
|
// just want to be sure that any following
|
|
// calls will clearly fail.
|
|
//
|
|
TotalSize = 0;
|
|
NumberOfCaches = 0;
|
|
GuardWord = 0;
|
|
GlobalDelete = False;
|
|
|
|
NewPage = NULL;
|
|
Heap = NULL;
|
|
Find = NULL;
|
|
Caches = NULL;
|
|
Array = NULL;
|
|
}
|
|
}
|
|
#ifdef DISABLE_STRUCTURED_EXCEPTIONS
|
|
#ifdef DEBUGGING
|
|
catch ( FAULT Message )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable, print a
|
|
// suitable message and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
|
|
DebugPrint( "Exception caught: %s\n",(char*) Message );
|
|
}
|
|
#endif
|
|
catch ( ... )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
}
|
|
#else
|
|
__except ( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
//
|
|
// It looks like the heap is corrupt. So
|
|
// lets just mark it as unusable and exit.
|
|
//
|
|
GuardWord = AllocationFailure;
|
|
}
|
|
#endif
|
|
}
|