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.
423 lines
15 KiB
423 lines
15 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 "Assembly.hpp"
|
|
#include "Prefetch.hpp"
|
|
#include "Spinlock.hpp"
|
|
#include "ZoneHeap.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 AlignmentMask = (sizeof(double)-1);
|
|
CONST SBIT32 FindCacheSize = 2048;
|
|
CONST SBIT32 FindCacheThreshold = 0;
|
|
CONST SBIT32 FindSize = 1024;
|
|
CONST SBIT32 Stride1 = 1024;
|
|
CONST SBIT32 Stride2 = 1024;
|
|
CONST SBIT32 ZonePageSize = 4096;
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* The description of the heap. */
|
|
/* */
|
|
/* A heap is a collection of fixed sized allocation caches. */
|
|
/* An allocation cache consists of an allocation size, the */
|
|
/* number of pre-built allocations to cache, a chunk size and */
|
|
/* a parent page size which is sub-divided to create elements */
|
|
/* for this cache. A heap consists of two arrays of caches. */
|
|
/* Each of these arrays has a stride (i.e. 'Stride1' and */
|
|
/* 'Stride2') which is typically the smallest common factor of */
|
|
/* all the allocation sizes in the array. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
STATIC ROCKALL::CACHE_DETAILS Caches1[] =
|
|
{
|
|
//
|
|
// Bucket Size Of Bucket Parent
|
|
// Size Cache Chunks Page Size
|
|
//
|
|
{ 4096, 8, 65536, 65536 },
|
|
{ 0,0,0,0 }
|
|
};
|
|
|
|
STATIC ROCKALL::CACHE_DETAILS Caches2[] =
|
|
{
|
|
//
|
|
// Bucket Size Of Bucket Parent
|
|
// Size Cache Chunks Page Size
|
|
//
|
|
{ 5120, 4, 65536, 65536 },
|
|
{ 6144, 4, 65536, 65536 },
|
|
{ 7168, 4, 65536, 65536 },
|
|
{ 8192, 8, 65536, 65536 },
|
|
{ 9216, 0, 65536, 65536 },
|
|
{ 10240, 0, 65536, 65536 },
|
|
{ 12288, 0, 65536, 65536 },
|
|
{ 16384, 2, 65536, 65536 },
|
|
{ 21504, 0, 65536, 65536 },
|
|
{ 32768, 0, 65536, 65536 },
|
|
|
|
{ 65536, 0, 65536, 65536 },
|
|
{ 65536, 0, 65536, 65536 },
|
|
{ 0,0,0,0 }
|
|
};
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* The description bit vectors. */
|
|
/* */
|
|
/* All heaps keep track of allocations using bit vectors. An */
|
|
/* allocation requires 2 bits to keep track of its state. The */
|
|
/* following array supplies the size of the available bit */
|
|
/* vectors measured in 32 bit words. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
STATIC int NewPageSizes[] = { 2,0 };
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Static data structures. */
|
|
/* */
|
|
/* The static data structures are initialized and prepared for */
|
|
/* use here. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
STATIC PREFETCH Prefetch;
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* 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. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
ZONE_HEAP::ZONE_HEAP
|
|
(
|
|
int MaxFreeSpace,
|
|
bool Recycle,
|
|
bool SingleImage,
|
|
bool ThreadSafe
|
|
) :
|
|
//
|
|
// Call the constructors for the contained classes.
|
|
//
|
|
ROCKALL
|
|
(
|
|
Caches1,
|
|
Caches2,
|
|
FindCacheSize,
|
|
FindCacheThreshold,
|
|
FindSize,
|
|
MaxFreeSpace,
|
|
NewPageSizes,
|
|
Recycle,
|
|
SingleImage,
|
|
Stride1,
|
|
Stride2,
|
|
ThreadSafe
|
|
)
|
|
{
|
|
AUTO ZONE NewZone = { NULL,NULL };
|
|
|
|
//
|
|
// Setup the heap structures.
|
|
//
|
|
MaxSize = ZonePageSize;
|
|
ThreadLocks = ThreadSafe;
|
|
Zone = NewZone;
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Delete all allocations. */
|
|
/* */
|
|
/* Delete all the heap allocations and return all the space */
|
|
/* back to the operating system. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
void ZONE_HEAP::DeleteAll( bool Recycle )
|
|
{
|
|
AUTO ZONE Update = { NULL,NULL };
|
|
|
|
//
|
|
// Delete all outstanding allocations.
|
|
//
|
|
ROCKALL::DeleteAll( Recycle );
|
|
|
|
//
|
|
// Delete the stale zone pointers.
|
|
//
|
|
WriteZone( & Update );
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Multiple memory allocations. */
|
|
/* */
|
|
/* We allocate by advancing a pinter down an array. This */
|
|
/* is very fast but means that it can not be deleted except */
|
|
/* by destroying the entire heap. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
bool ZONE_HEAP::MultipleNew
|
|
(
|
|
int *Actual,
|
|
void *Array[],
|
|
int Requested,
|
|
int Size,
|
|
int *Space,
|
|
bool Zero
|
|
)
|
|
{
|
|
//
|
|
// We simply call 'New' to create each element
|
|
// for a zone heap.
|
|
//
|
|
for ( (*Actual)=0;(*Actual) < Requested;(*Actual) ++ )
|
|
{
|
|
REGISTER VOID **Current = & Array[ (*Actual) ];
|
|
|
|
//
|
|
// Create an allocation.
|
|
//
|
|
(*Current) = (ZONE_HEAP::New( Size,Space,Zero ));
|
|
|
|
//
|
|
// Exit if there is no more space.
|
|
//
|
|
if ( (*Current) == NULL )
|
|
{ return false; }
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Memory allocation. */
|
|
/* */
|
|
/* We allocate by advancing a pinter down an array. This */
|
|
/* is very fast but means that it can not be deleted except */
|
|
/* by destroying the entire heap. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
void *ZONE_HEAP::New( int Size,int *Space,bool Zero )
|
|
{
|
|
//
|
|
// We would really hope that nobody would ask
|
|
// for a negative amount of memory but just to
|
|
// be sure we verify that this is not the case.
|
|
//
|
|
if ( Size >= 0 )
|
|
{
|
|
AUTO SBIT32 NewSize = ((Size + AlignmentMask) & ~AlignmentMask);
|
|
AUTO ZONE Original;
|
|
AUTO ZONE Update;
|
|
|
|
//
|
|
// We would hope to create the allocation on the
|
|
// first try but there is a possibility that it
|
|
// may take serveral tries.
|
|
do
|
|
{
|
|
//
|
|
// Extract a copy of the current zone pointers
|
|
// into local variables.
|
|
//
|
|
Original = Zone;
|
|
Update = Original;
|
|
|
|
//
|
|
// We need to ensure that there is enough space
|
|
// in the zone for the current allocation.
|
|
//
|
|
if
|
|
(
|
|
(Update.Start == NULL)
|
|
||
|
|
((Update.Start += NewSize) > Update.End)
|
|
)
|
|
{
|
|
//
|
|
// We do not have enough space. If the size
|
|
// seems reasonable then get a new block from
|
|
// Rockall. If not just pass the request along
|
|
// to Rockall.
|
|
//
|
|
if ( NewSize <= (MaxSize / 2) )
|
|
{
|
|
STATIC SPINLOCK Spinlock;
|
|
|
|
//
|
|
// We need to create a new zone page
|
|
// so claim a lock.
|
|
//
|
|
Spinlock.ClaimLock();
|
|
|
|
//
|
|
// We may find that the zone has
|
|
// already been updated. If so
|
|
// just exit.
|
|
//
|
|
if ( Update.End == Zone.End )
|
|
{
|
|
//
|
|
// Try to allocate a new zone
|
|
// block.
|
|
//
|
|
Update.Start = ((CHAR*) ROCKALL::New( MaxSize ));
|
|
|
|
//
|
|
// Verify we were able to create
|
|
// a new zone page.
|
|
//
|
|
if ( Update.Start != NULL )
|
|
{ Update.End = (Update.Start + MaxSize); }
|
|
else
|
|
{ Update.End = NULL; }
|
|
|
|
//
|
|
// Update the zone.
|
|
//
|
|
WriteZone( & Update );
|
|
}
|
|
|
|
//
|
|
// Release the lock.
|
|
//
|
|
Spinlock.ReleaseLock();
|
|
|
|
//
|
|
// If we were unable to get more
|
|
// space then exit.
|
|
//
|
|
if ( Update.Start == NULL )
|
|
{ return NULL; }
|
|
}
|
|
else
|
|
{ return (ROCKALL::New( Size,Space,Zero )); }
|
|
}
|
|
}
|
|
while ( ! UpdateZone( & Original,& Update ) );
|
|
|
|
//
|
|
// Prefetch the first cache line of
|
|
// the allocation if we are running
|
|
// a Pentium III or better.
|
|
//
|
|
Prefetch.L1( ((CHAR*) Original.Start),1 );
|
|
|
|
//
|
|
// If the caller wants to know the real
|
|
// size them we supply it.
|
|
//
|
|
if ( Space != NULL )
|
|
{ (*Space) = NewSize; }
|
|
|
|
//
|
|
// If we need to zero the allocation
|
|
// we do it here.
|
|
//
|
|
if ( Zero )
|
|
{ ZeroMemory( Original.Start,NewSize ); }
|
|
|
|
//
|
|
// Exit and return the address.
|
|
//
|
|
return (Original.Start);
|
|
}
|
|
else
|
|
{ return NULL; }
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Update the zone. */
|
|
/* */
|
|
/* Ww update the zone when we do an allocation. We do this */
|
|
/* atomically if there are multiple threads. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
bool ZONE_HEAP::UpdateZone( ZONE *Original,ZONE *Update )
|
|
{
|
|
//
|
|
// Do we need to allow for multiple threads. If
|
|
// so we need to do the update atomically. If
|
|
// not then a simple assignment is fine.
|
|
//
|
|
if ( ThreadLocks )
|
|
{
|
|
REGISTER SBIT64 FinalValue =
|
|
(
|
|
ASSEMBLY::AtomicCompareExchange64
|
|
(
|
|
((SBIT64*) & Zone),
|
|
(*((SBIT64*) Update)),
|
|
(*((SBIT64*) Original))
|
|
)
|
|
);
|
|
|
|
return (FinalValue == (*((SBIT64*) Original)));
|
|
}
|
|
else
|
|
{
|
|
Zone = (*Update);
|
|
|
|
return True;
|
|
}
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* Class destructor. */
|
|
/* */
|
|
/* Destory the heap. */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
ZONE_HEAP::~ZONE_HEAP( VOID )
|
|
{ /* void */ }
|