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.
1182 lines
35 KiB
1182 lines
35 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 "Dll.hpp"
|
|
#include "List.hpp"
|
|
#include "New.hpp"
|
|
#include "Sharelock.hpp"
|
|
#include "SmpHeap.hpp"
|
|
#include "Tls.hpp"
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Structures local to the class. */
|
|
/* */
|
|
/* The structures supplied here describe the layout of the */
|
|
/* private per thread heap structures. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
typedef struct PRIVATE_HEAP : public LIST
|
|
{
|
|
SMP_HEAP_TYPE Heap;
|
|
}
|
|
PRIVATE_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. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
SMP_HEAP::SMP_HEAP
|
|
(
|
|
int MaxFreeSpace,
|
|
bool Recycle,
|
|
bool SingleImage,
|
|
bool ThreadSafe,
|
|
bool DeleteHeapOnExit
|
|
) :
|
|
//
|
|
// Call the constructors for the contained classes.
|
|
//
|
|
MaxFreeSpace(MaxFreeSpace),
|
|
Recycle(Recycle),
|
|
SingleImage(True),
|
|
ThreadSafe(ThreadSafe),
|
|
SMP_HEAP_TYPE( 0,false,true,true )
|
|
{
|
|
//
|
|
// Setup various control variables.
|
|
//
|
|
Active = false;
|
|
DeleteOnExit = DeleteHeapOnExit;
|
|
|
|
//
|
|
// Create the linked list headers and a thread
|
|
// local store variable to point at each threads
|
|
// private heap.
|
|
//
|
|
ActiveHeaps = ((LIST*) SMP_HEAP_TYPE::New( sizeof(LIST) ));
|
|
DllEvents = ((DLL*) SMP_HEAP_TYPE::New( sizeof(DLL) ));
|
|
FreeHeaps = ((LIST*) SMP_HEAP_TYPE::New( sizeof(LIST) ));
|
|
HeapWalk = NULL;
|
|
Tls = ((TLS*) SMP_HEAP_TYPE::New( sizeof(TLS) ));
|
|
|
|
//
|
|
// We can only activate the the heap if we manage
|
|
// to allocate space we requested.
|
|
//
|
|
if
|
|
(
|
|
(ActiveHeaps != NULL)
|
|
&&
|
|
(DllEvents != NULL)
|
|
&&
|
|
(FreeHeaps != NULL)
|
|
&&
|
|
(Tls != NULL)
|
|
)
|
|
{
|
|
//
|
|
// Execute the constructors for each linked list
|
|
// and for the thread local store.
|
|
//
|
|
PLACEMENT_NEW( ActiveHeaps,LIST );
|
|
#ifdef COMPILING_ROCKALL_DLL
|
|
PLACEMENT_NEW( DllEvents,DLL )( ThreadDetach,this );
|
|
#endif
|
|
PLACEMENT_NEW( FreeHeaps,LIST );
|
|
PLACEMENT_NEW( Tls,TLS );
|
|
|
|
//
|
|
// Activate the heap.
|
|
//
|
|
ActiveLocks = 0;
|
|
|
|
Active = true;
|
|
}
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Memory deallocation. */
|
|
/* */
|
|
/* When we delete an allocation we try to delete it in the */
|
|
/* private per thread heap if it exists. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
bool SMP_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 )
|
|
{
|
|
REGISTER PRIVATE_HEAP *PrivateHeap =
|
|
((PRIVATE_HEAP*) Tls -> GetPointer());
|
|
|
|
//
|
|
// We need to examine the TLS pointer to make
|
|
// sure we have a heap for the current thread.
|
|
// If not we just use the internal heap.
|
|
//
|
|
if ( PrivateHeap != NULL )
|
|
{ return (PrivateHeap -> Heap.Delete( Address,Size )); }
|
|
else
|
|
{ return (SMP_HEAP_TYPE::Delete( Address,Size )); }
|
|
}
|
|
else
|
|
{ return false; }
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Delete all allocations. */
|
|
/* */
|
|
/* We walk the list of all the heaps and instruct each heap */
|
|
/* to delete everything. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
void SMP_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 PRIVATE_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 = ((PRIVATE_HEAP*) ActiveHeaps -> First());
|
|
(Current != NULL);
|
|
Current = ((PRIVATE_HEAP*) Current -> Next())
|
|
)
|
|
{ Current -> Heap.DeleteAll( Recycle ); }
|
|
|
|
//
|
|
// Release the lock.
|
|
//
|
|
Sharelock.ReleaseShareLock();
|
|
|
|
//
|
|
// Claim a process wide exclusive lock
|
|
// to ensure the list of heaps does
|
|
// not change until we have finished.
|
|
//
|
|
Sharelock.ClaimExclusiveLock();
|
|
|
|
//
|
|
// We walk the free list of heaps and
|
|
// delete everything.
|
|
//
|
|
for
|
|
(
|
|
Current = ((PRIVATE_HEAP*) FreeHeaps -> First());
|
|
Current != NULL;
|
|
Current = ((PRIVATE_HEAP*) FreeHeaps -> First())
|
|
)
|
|
|
|
{
|
|
//
|
|
// Delete each heap from the free list,
|
|
// call the destructor and delete any
|
|
// associated space.
|
|
//
|
|
Current -> Delete( FreeHeaps );
|
|
|
|
PLACEMENT_DELETE( Current,PRIVATE_HEAP );
|
|
|
|
SMP_HEAP_TYPE::Delete( Current );
|
|
}
|
|
|
|
//
|
|
// Release the lock.
|
|
//
|
|
Sharelock.ReleaseExclusiveLock();
|
|
}
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Memory allocation details. */
|
|
/* */
|
|
/* When we are asked for details we try to the private per */
|
|
/* thread heap if it exists. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
bool SMP_HEAP::Details( void *Address,int *Space )
|
|
{
|
|
//
|
|
// Although it is very rare there is a chance
|
|
// that we failed to build the basic heap structures.
|
|
//
|
|
if ( Active )
|
|
{
|
|
REGISTER PRIVATE_HEAP *PrivateHeap =
|
|
((PRIVATE_HEAP*) Tls -> GetPointer());
|
|
|
|
//
|
|
// We need to examine the TLS pointer to make
|
|
// sure we have a heap for the current thread.
|
|
// If not we just use the internal heap.
|
|
//
|
|
if ( PrivateHeap != NULL )
|
|
{ return (PrivateHeap -> Heap.Details( Address,Space )); }
|
|
else
|
|
{ return (SMP_HEAP_TYPE::Details( Address,Space )); }
|
|
}
|
|
else
|
|
{ return false; }
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Extract the private heap. */
|
|
/* */
|
|
/* We need to provide all threads with a private heap. When */
|
|
/* we discover we need another heap we either recycle an */
|
|
/* existing heap or create a new one. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
PRIVATE_HEAP *SMP_HEAP::GetPrivateHeap( void )
|
|
{
|
|
REGISTER PRIVATE_HEAP *PrivateHeap = ((PRIVATE_HEAP*) Tls -> GetPointer());
|
|
|
|
//
|
|
// We need to examine the TLS pointer to make
|
|
// sure we have a heap for the current thread.
|
|
// If not we just create a new heap.
|
|
//
|
|
if ( PrivateHeap == NULL )
|
|
{
|
|
//
|
|
// Claim a process wide exclusive lock
|
|
// to ensure the list of heaps does
|
|
// not change until we have finished.
|
|
//
|
|
Sharelock.ClaimExclusiveLock();
|
|
|
|
//
|
|
// When there is an available free heap
|
|
// then extract it from the free list.
|
|
//
|
|
if ( (PrivateHeap = ((PRIVATE_HEAP*) FreeHeaps -> First())) != NULL )
|
|
{
|
|
//
|
|
// Delete the heap from the list of
|
|
// of free heaps.
|
|
//
|
|
PrivateHeap -> Delete( FreeHeaps );
|
|
}
|
|
|
|
//
|
|
// When there is no available free heap then
|
|
// we try to make a new heap.
|
|
//
|
|
if ( PrivateHeap == NULL )
|
|
{
|
|
//
|
|
// Release the lock.
|
|
//
|
|
Sharelock.ReleaseExclusiveLock();
|
|
|
|
//
|
|
// Allocate space for the new private per
|
|
// thread heap.
|
|
//
|
|
PrivateHeap =
|
|
((PRIVATE_HEAP*) SMP_HEAP_TYPE::New( sizeof(PRIVATE_HEAP) ));
|
|
|
|
//
|
|
// We need to ensure that the allocation
|
|
// worked before we try to add it into
|
|
// the list of active heaps.
|
|
//
|
|
if ( PrivateHeap != NULL )
|
|
{
|
|
//
|
|
// Activate the new heap.
|
|
//
|
|
PLACEMENT_NEW( PrivateHeap,LIST );
|
|
|
|
PLACEMENT_NEW( & PrivateHeap -> Heap,SMP_HEAP_TYPE )
|
|
(
|
|
MaxFreeSpace,
|
|
Recycle,
|
|
SingleImage,
|
|
ThreadSafe
|
|
);
|
|
|
|
//
|
|
// If the heap constructor failed, then
|
|
// do not put this heap in the list of
|
|
// active heaps, and return NULL back to
|
|
// the caller. A side-effect of this is
|
|
// that the allocation for the PrivateHeap
|
|
// will be leaked.
|
|
//
|
|
if (! PrivateHeap->Heap.Available())
|
|
{
|
|
PrivateHeap = NULL;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Claim a process wide exclusive lock
|
|
// to ensure the list of heaps does
|
|
// not change until we have finished.
|
|
//
|
|
Sharelock.ClaimExclusiveLock();
|
|
}
|
|
|
|
//
|
|
// We would expect to have a new heap by this
|
|
// point. If not then we just exit.
|
|
//
|
|
if ( PrivateHeap != NULL )
|
|
{
|
|
//
|
|
// Insert the new heap in the list
|
|
// of active heaps.
|
|
//
|
|
PrivateHeap -> Insert( ActiveHeaps );
|
|
|
|
//
|
|
// Nasty: we may have an outstanding lock
|
|
// on the rest of the heaps. If so claim
|
|
// it for this heap as well.
|
|
//
|
|
if ( ActiveLocks > 0 )
|
|
{ PrivateHeap -> Heap.LockAll(); }
|
|
|
|
//
|
|
// Update the TLS pointer.
|
|
//
|
|
Tls -> SetPointer( ((VOID*) PrivateHeap) );
|
|
}
|
|
|
|
//
|
|
// Release the lock.
|
|
//
|
|
Sharelock.ReleaseExclusiveLock();
|
|
}
|
|
|
|
return PrivateHeap;
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* A known area. */
|
|
/* */
|
|
/* When we are asked about an address we try to the private per */
|
|
/* thread heap if it exists. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
bool SMP_HEAP::KnownArea( void *Address )
|
|
{
|
|
//
|
|
// Although it is very rare there is a chance
|
|
// that we failed to build the basic heap structures.
|
|
//
|
|
if ( Active )
|
|
{
|
|
REGISTER PRIVATE_HEAP *PrivateHeap =
|
|
((PRIVATE_HEAP*) Tls -> GetPointer());
|
|
|
|
//
|
|
// We need to examine the TLS pointer to make
|
|
// sure we have a heap for the current thread.
|
|
// If not we just use the internal heap.
|
|
//
|
|
if ( PrivateHeap != NULL )
|
|
{ return (PrivateHeap -> Heap.KnownArea( Address )); }
|
|
else
|
|
{ return (SMP_HEAP_TYPE::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 SMP_HEAP::LockAll( VOID )
|
|
{
|
|
//
|
|
// Although it is very rare there is a chance
|
|
// that we failed to build the basic heap structures.
|
|
//
|
|
if ( Active )
|
|
{
|
|
REGISTER PRIVATE_HEAP *Current;
|
|
|
|
//
|
|
// Claim a process wide shared lock
|
|
// to ensure the list of heaps does
|
|
// not change until we have finished.
|
|
//
|
|
Sharelock.ClaimShareLock();
|
|
|
|
//
|
|
// Nasty: We may actually create or delete
|
|
// a heap between locking all the heaps and
|
|
// unlocking them. Thus, we need to keep a
|
|
// count of the outstanding locks to keep
|
|
// this all consistent.
|
|
//
|
|
ASSEMBLY::AtomicIncrement( ((SBIT32*) & ActiveLocks) );
|
|
|
|
//
|
|
// You just have to hope the user knows
|
|
// what they are doing as we claim all
|
|
// of the heap locks.
|
|
//
|
|
for
|
|
(
|
|
Current = ((PRIVATE_HEAP*) ActiveHeaps -> First());
|
|
(Current != NULL);
|
|
Current = ((PRIVATE_HEAP*) Current -> Next())
|
|
)
|
|
{ Current -> Heap.LockAll(); }
|
|
|
|
//
|
|
// Release the lock.
|
|
//
|
|
Sharelock.ReleaseShareLock();
|
|
}
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Multiple memory deallocations. */
|
|
/* */
|
|
/* When we delete multiple allocations we try to delete them on */
|
|
/* the private per thread heap if it exists. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
bool SMP_HEAP::MultipleDelete
|
|
(
|
|
int Actual,
|
|
void *Array[],
|
|
int Size
|
|
)
|
|
{
|
|
//
|
|
// Although it is very rare there is a chance
|
|
// that we failed to build the basic heap structures.
|
|
//
|
|
if ( Active )
|
|
{
|
|
REGISTER PRIVATE_HEAP *PrivateHeap =
|
|
((PRIVATE_HEAP*) Tls -> GetPointer());
|
|
|
|
//
|
|
// We need to examine the TLS pointer to make
|
|
// sure we have a heap for the current thread.
|
|
// If not we just use the internal heap.
|
|
//
|
|
if ( PrivateHeap != NULL )
|
|
{ return (PrivateHeap -> Heap.MultipleDelete(Actual,Array,Size)); }
|
|
else
|
|
{ return (SMP_HEAP_TYPE::MultipleDelete( Actual,Array,Size )); }
|
|
}
|
|
else
|
|
{ return false; }
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Multiple memory allocations. */
|
|
/* */
|
|
/* We allocate space for the current thread from the local */
|
|
/* private per thread heap. If we do not have a local private */
|
|
/* per thread heap then we create one and use it. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
bool SMP_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 PRIVATE_HEAP *PrivateHeap = GetPrivateHeap();
|
|
|
|
//
|
|
// We need to examine private heap to make
|
|
// sure we have a heap for the current thread.
|
|
//
|
|
if ( PrivateHeap != NULL )
|
|
{
|
|
//
|
|
// Allocate the memory requested on the local
|
|
// private per thread heap.
|
|
//
|
|
return
|
|
(
|
|
PrivateHeap -> Heap.MultipleNew
|
|
(
|
|
Actual,
|
|
Array,
|
|
Requested,
|
|
Size,
|
|
Space,
|
|
Zero
|
|
)
|
|
);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We were unable to create a new heap
|
|
// so exit.
|
|
//
|
|
(*Actual) = 0;
|
|
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We are not active yet so exit.
|
|
//
|
|
(*Actual) = 0;
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Memory allocation. */
|
|
/* */
|
|
/* We allocate space for the current thread from the local */
|
|
/* private per thread heap. If we do not have a local private */
|
|
/* per thread heap then we create one and use it. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
void *SMP_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 PRIVATE_HEAP *PrivateHeap = GetPrivateHeap();
|
|
|
|
//
|
|
// We need to examine private heap to make
|
|
// sure we have a heap for the current thread.
|
|
//
|
|
if ( PrivateHeap != NULL )
|
|
{ return (PrivateHeap -> Heap.New( Size,Space,Zero )); }
|
|
else
|
|
{ return NULL; }
|
|
}
|
|
else
|
|
{ return NULL; }
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Memory reallocation. */
|
|
/* */
|
|
/* We reallocate space for the current thread on the local */
|
|
/* private per thread heap. If we do not have a local private */
|
|
/* per thread heap then we create one and use it. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
void *SMP_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 )
|
|
{
|
|
REGISTER PRIVATE_HEAP *PrivateHeap = GetPrivateHeap();
|
|
|
|
//
|
|
// We need to examine private heap to make
|
|
// sure we have a heap for the current thread.
|
|
//
|
|
if ( PrivateHeap != NULL )
|
|
{
|
|
//
|
|
// Reallocate the memory requested on
|
|
// the local private per thread heap.
|
|
//
|
|
return
|
|
(
|
|
PrivateHeap -> Heap.Resize
|
|
(
|
|
Address,
|
|
NewSize,
|
|
Move,
|
|
Space,
|
|
NoDelete,
|
|
Zero
|
|
)
|
|
);
|
|
}
|
|
else
|
|
{ return NULL; }
|
|
}
|
|
else
|
|
{ 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 *SMP_HEAP::SpecialNew( int Size )
|
|
{ return SMP_HEAP_TYPE::New( Size ); }
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Delete a local heap. */
|
|
/* */
|
|
/* Delete a local per thread heap and return all the outstanding */
|
|
/* memory to the operating system. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
void SMP_HEAP::ThreadDetach( void *Parameter,int Reason )
|
|
{
|
|
|
|
//
|
|
// We only take any action on a thread detach
|
|
// notification. All other notifications are
|
|
// not actioned.
|
|
//
|
|
if ( Reason == DLL_THREAD_DETACH )
|
|
{
|
|
REGISTER SMP_HEAP *SmpHeap = ((SMP_HEAP*) Parameter);
|
|
|
|
//
|
|
// Claim a process wide exclusive lock
|
|
// to ensure the list of heaps does
|
|
// not change until we have finished.
|
|
//
|
|
Sharelock.ClaimExclusiveLock();
|
|
|
|
//
|
|
// There is a nasty situation where the
|
|
// destructor is called before a thread
|
|
// fully terminates so ensure the heap
|
|
// is still active.
|
|
//
|
|
if ( SmpHeap -> Active )
|
|
{
|
|
REGISTER PRIVATE_HEAP *PrivateHeap =
|
|
((PRIVATE_HEAP*) SmpHeap -> Tls -> GetPointer());
|
|
|
|
//
|
|
// We need to examine the TLS pointer to make
|
|
// sure we have a heap for the current thread.
|
|
// If not we just use the internal heap.
|
|
//
|
|
if ( PrivateHeap != NULL )
|
|
{
|
|
//
|
|
// Update the TLS pointer.
|
|
//
|
|
SmpHeap -> Tls -> SetPointer( NULL );
|
|
|
|
//
|
|
// Insert the new heap in the list
|
|
// of active heaps.
|
|
//
|
|
PrivateHeap -> Delete( SmpHeap -> ActiveHeaps );
|
|
|
|
//
|
|
// When we are not allowed to delete
|
|
// the heap we put it on the free list.
|
|
//
|
|
if ( ! SmpHeap -> DeleteOnExit )
|
|
{ PrivateHeap -> Insert( SmpHeap -> FreeHeaps ); }
|
|
|
|
//
|
|
// Nasty: we may have an outstanding lock
|
|
// on this heap. If so then free it.
|
|
//
|
|
if ( SmpHeap -> ActiveLocks > 0 )
|
|
{ PrivateHeap -> Heap.UnlockAll(); }
|
|
|
|
//
|
|
// Release the lock.
|
|
//
|
|
Sharelock.ReleaseExclusiveLock();
|
|
|
|
//
|
|
// When we are allowed to delete the
|
|
// heap we do it here.
|
|
//
|
|
if ( ! SmpHeap -> DeleteOnExit )
|
|
{
|
|
//
|
|
// Truncate the heap to remove any
|
|
// unwanted space.
|
|
//
|
|
PrivateHeap -> Heap.Truncate( 0 );
|
|
}
|
|
else
|
|
{
|
|
#ifdef COMPLAIN_ABOUT_SMP_HEAP_LEAKS
|
|
//
|
|
// We have finished with the private
|
|
// heap so now is a good time to complain
|
|
// about leaks.
|
|
//
|
|
PrivateHeap -> Heap.HeapLeaks();
|
|
|
|
#endif
|
|
//
|
|
// We have finished with the private
|
|
// heap so delete it.
|
|
//
|
|
PLACEMENT_DELETE( PrivateHeap,PRIVATE_HEAP );
|
|
|
|
SmpHeap -> SMP_HEAP_TYPE::Delete( PrivateHeap );
|
|
}
|
|
}
|
|
else
|
|
{ Sharelock.ReleaseExclusiveLock(); }
|
|
}
|
|
else
|
|
{ Sharelock.ReleaseExclusiveLock(); }
|
|
}
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* 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 SMP_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 PRIVATE_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 = ((PRIVATE_HEAP*) ActiveHeaps -> First());
|
|
(Current != NULL);
|
|
Current = ((PRIVATE_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 SMP_HEAP::UnlockAll( VOID )
|
|
{
|
|
//
|
|
// Although it is very rare there is a chance
|
|
// that we failed to build the basic heap structures.
|
|
//
|
|
if ( Active )
|
|
{
|
|
REGISTER PRIVATE_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 = ((PRIVATE_HEAP*) ActiveHeaps -> First());
|
|
(Current != NULL);
|
|
Current = ((PRIVATE_HEAP*) Current -> Next())
|
|
)
|
|
{ Current -> Heap.UnlockAll(); }
|
|
|
|
//
|
|
// Nasty: We may actually create or delete
|
|
// a private heap for a thread between
|
|
// locking an 'SMP_HEAP' and unlocking it.
|
|
// Thus, we need to keep a count of the
|
|
// outstanding locks to keep this all
|
|
// consistent.
|
|
//
|
|
ASSEMBLY::AtomicDecrement( ((SBIT32*) & ActiveLocks) );
|
|
|
|
//
|
|
// Release the lock.
|
|
//
|
|
Sharelock.ReleaseShareLock();
|
|
}
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Verify a memory allocation details. */
|
|
/* */
|
|
/* When we verify an allocation we try to verify it in the */
|
|
/* private per thread heap if it exists. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
bool SMP_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 )
|
|
{
|
|
REGISTER PRIVATE_HEAP *PrivateHeap =
|
|
((PRIVATE_HEAP*) Tls -> GetPointer());
|
|
|
|
//
|
|
// We need to examine the TLS pointer to make
|
|
// sure we have a heap for the current thread.
|
|
// If not we just use the internal heap.
|
|
//
|
|
if ( PrivateHeap != NULL )
|
|
{ return (PrivateHeap -> Heap.Verify( Address,Space )); }
|
|
else
|
|
{ return (SMP_HEAP_TYPE::Verify( Address,Space )); }
|
|
}
|
|
else
|
|
{ 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 SMP_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 'SMP_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 = ((PRIVATE_HEAP*) ActiveHeaps -> 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 = ((PRIVATE_HEAP*) HeapWalk -> Next()); }
|
|
|
|
//
|
|
// Release the lock.
|
|
//
|
|
Sharelock.ReleaseShareLock();
|
|
|
|
return (HeapWalk != NULL);
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Class destructor. */
|
|
/* */
|
|
/* Destory the heap. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
SMP_HEAP::~SMP_HEAP( void )
|
|
{
|
|
//
|
|
// Although it is very rare there is a chance
|
|
// that we failed to build the basic heap structures.
|
|
//
|
|
if ( Active )
|
|
{
|
|
REGISTER PRIVATE_HEAP *Current;
|
|
|
|
//
|
|
// Deactivate the heap.
|
|
//
|
|
Active = false;
|
|
|
|
//
|
|
// Claim a process wide exclusive lock
|
|
// to ensure the list of heaps does
|
|
// not change until we have finished.
|
|
//
|
|
Sharelock.ClaimExclusiveLock();
|
|
|
|
//
|
|
// We walk the active list of heaps and
|
|
// delete everything.
|
|
//
|
|
for
|
|
(
|
|
Current = ((PRIVATE_HEAP*) ActiveHeaps -> First());
|
|
Current != NULL;
|
|
Current = ((PRIVATE_HEAP*) ActiveHeaps -> First())
|
|
)
|
|
{
|
|
//
|
|
// Delete each heap from the active list,
|
|
// call the destructor and delete any
|
|
// associated space.
|
|
//
|
|
Current -> Delete( ActiveHeaps );
|
|
#ifdef COMPLAIN_ABOUT_SMP_HEAP_LEAKS
|
|
|
|
//
|
|
// We have finished with the private
|
|
// heap so now is a good time to complain
|
|
// about leaks.
|
|
//
|
|
Current -> Heap.HeapLeaks();
|
|
#endif
|
|
|
|
//
|
|
// We have finished with the private
|
|
// heap so delete it.
|
|
//
|
|
PLACEMENT_DELETE( Current,PRIVATE_HEAP );
|
|
|
|
SMP_HEAP_TYPE::Delete( Current );
|
|
}
|
|
|
|
//
|
|
// We walk the free list of heaps and
|
|
// delete everything.
|
|
//
|
|
for
|
|
(
|
|
Current = ((PRIVATE_HEAP*) FreeHeaps -> First());
|
|
Current != NULL;
|
|
Current = ((PRIVATE_HEAP*) FreeHeaps -> First())
|
|
)
|
|
|
|
{
|
|
//
|
|
// Delete each heap from the active list,
|
|
// call the destructor and delete any
|
|
// associated space.
|
|
//
|
|
Current -> Delete( FreeHeaps );
|
|
#ifdef COMPLAIN_ABOUT_SMP_HEAP_LEAKS
|
|
|
|
//
|
|
// We have finished with the private
|
|
// heap so now is a good time to complain
|
|
// about leaks.
|
|
//
|
|
Current -> Heap.HeapLeaks();
|
|
#endif
|
|
|
|
//
|
|
// We have finished with the private
|
|
// heap so delete it.
|
|
//
|
|
PLACEMENT_DELETE( Current,PRIVATE_HEAP );
|
|
|
|
SMP_HEAP_TYPE::Delete( Current );
|
|
}
|
|
|
|
//
|
|
// Release the lock.
|
|
//
|
|
Sharelock.ReleaseExclusiveLock();
|
|
|
|
//
|
|
// Call the list and TLS destructors.
|
|
//
|
|
PLACEMENT_DELETE( Tls,TLS );
|
|
PLACEMENT_DELETE( FreeHeaps,LIST );
|
|
#ifdef COMPILING_ROCKALL_DLL
|
|
PLACEMENT_DELETE( DllEvents,DLL );
|
|
#endif
|
|
PLACEMENT_DELETE( ActiveHeaps,LIST );
|
|
|
|
//
|
|
// Delete the space.
|
|
//
|
|
SMP_HEAP_TYPE::Delete( Tls );
|
|
SMP_HEAP_TYPE::Delete( FreeHeaps );
|
|
SMP_HEAP_TYPE::Delete( DllEvents );
|
|
SMP_HEAP_TYPE::Delete( ActiveHeaps );
|
|
|
|
//
|
|
// Zero the pointers just to be tidy.
|
|
//
|
|
Tls = NULL;
|
|
HeapWalk = NULL;
|
|
FreeHeaps = NULL;
|
|
DllEvents = NULL;
|
|
ActiveHeaps = NULL;
|
|
}
|
|
}
|