Leaked source code of windows server 2003
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.
 
 
 
 
 
 

920 lines
28 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 "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;
}
}