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.
 
 
 
 
 
 

1262 lines
37 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 "HeapPCH.hpp"
#include "Cache.hpp"
#include "New.hpp"
#include "NewPage.hpp"
#include "Rockall.hpp"
/********************************************************************/
/* */
/* Constants local to the class. */
/* */
/* The constants set overall limits on the number and size of */
/* page descriptions for pages within the memory allocator. */
/* */
/********************************************************************/
CONST SBIT32 MinNewPages = 1;
CONST SBIT32 VectorRange = ((2 << 15) - 1);
/********************************************************************/
/* */
/* Class constructor. */
/* */
/* A 'PAGE' structure has various fixed fields and a variable */
/* sized allocation bit vector. When this class is initialized */
/* the user is required to supply us with an array that details */
/* the sizes of allocation bit vectors supported. */
/* */
/********************************************************************/
NEW_PAGE::NEW_PAGE
(
FIND *NewFind,
SBIT32 NewPageSizes[],
ROCKALL *NewRockall,
SBIT32 Size,
BOOLEAN NewThreadSafe
)
{
REGISTER SBIT32 DefaultRootSize = (NewRockall -> NaturalSize());
REGISTER SBIT32 ReservedBytes = (Size * sizeof(NEW_PAGES));
REGISTER SBIT32 SpareBytes = (DefaultRootSize - ReservedBytes);
REGISTER SBIT32 StackSize = (SpareBytes / sizeof(VOID*));
//
// We need to make sure that we appear to have a valid
// array of 'NewPageSizes' and that the bit vector sizes
// do not exceed the memory addressing range.
//
if
(
PowerOfTwo( DefaultRootSize )
&&
(DefaultRootSize >= PageSize())
&&
(Size >= MinNewPages)
&&
((NewPageSizes[ (Size-1) ] * OverheadBitsPerWord) <= VectorRange)
)
{
REGISTER VOID *NewMemory =
(
NewRockall -> NewArea
(
(DefaultRootSize-1),
DefaultRootSize,
False
)
);
//
// We are in big trouble if we can not allocate space
// to store this initial control information. If the
// allocation fails we are forced to exit and the whole
// memory allocator becomes unavailable.
//
if ( NewMemory != AllocationFailure )
{
REGISTER SBIT32 Count;
REGISTER SBIT32 LastSize = 0;
//
// We are now ready to setup the configuration
// information.
//
MaxCacheStack = 0;
MaxNewPages = Size;
MaxStack = StackSize;
NaturalSize = DefaultRootSize;
RootCoreSize = DefaultRootSize;
RootStackSize = 0;
ThreadSafe = NewThreadSafe;
TopOfStack = 0;
Version = 0;
CacheStack = NULL;
NewPages = ((NEW_PAGES*) NewMemory);
Stack = ((VOID**) & NewPages[ Size ]);
Find = NewFind;
Rockall = NewRockall;
TopCache = NULL;
//
// Create a lists for the various page
// sizes and prepare them for use.
//
for ( Count=0;Count < Size;Count ++ )
{
REGISTER SBIT32 CurrentSize = NewPageSizes[ Count ];
if ( CurrentSize > LastSize )
{
REGISTER NEW_PAGES *NewPage = & NewPages[ Count ];
//
// Create a list for the current
// size and fill in all the related
// details.
//
NewPage -> Elements = (CurrentSize * OverheadBitsPerWord);
PLACEMENT_NEW( & NewPage -> ExternalList,LIST );
PLACEMENT_NEW( & NewPage -> FullList,LIST );
PLACEMENT_NEW( & NewPage -> FreeList,LIST );
NewPage -> Size = (CurrentSize * sizeof(BIT32));
LastSize = CurrentSize;
}
else
{ Failure( "Sizes in constructor for NEW_PAGES" ); }
}
}
else
{ Failure( "No memory in constructor for NEW_PAGES" ); }
}
else
{ Failure( "Setup of pages in constructor for NEW_PAGES" ); }
}
/********************************************************************/
/* */
/* Create a new page. */
/* */
/* Create a new 'PAGE' structure and prepare it for use. If */
/* we don't already have any pages of the required size then */
/* allocate memory, create new 'PAGE' structures and link them */
/* into the appropriate free chain. */
/* */
/********************************************************************/
PAGE *NEW_PAGE::CreatePage( CACHE *Cache,SBIT32 NewSize )
{
REGISTER PAGE *NewPage = ((PAGE*) AllocationFailure);
REGISTER SBIT16 SizeKey = (Cache -> GetSizeKey());
//
// All allocations are made from fixed sized
// pages. These pages have a bit vector to
// keep track of which elements are allocated
// and available. The 'SizeKey' is an index
// into 'NewPages[]' that will supply a page
// that has a big enough the bit vector.
//
#ifdef DEBUGGING
if ( (SizeKey >= 0) && (SizeKey < MaxNewPages) )
{
#endif
REGISTER NEW_PAGES *Current;
//
// When there is a potential for multiple threads
// we claim the lock.
//
ClaimNewPageLock();
//
// We allocate 'PAGE' structures as we need them
// and link them together in the free list.
// If we don't have any structures available we
// allocate some more and add tem to the list.
//
if ( (Current = & NewPages[ SizeKey ]) -> FreeList.EndOfList() )
{
REGISTER SBIT32 ArrayElements = (Current -> Size - MinVectorSize);
REGISTER SBIT32 ArraySize = (ArrayElements * sizeof(BIT32));
REGISTER SBIT32 TotalSize = (sizeof(PAGE) + ArraySize);
REGISTER SBIT32 FinalSize = CacheAlignSize( TotalSize );
REGISTER SBIT32 TotalPages = (NaturalSize / FinalSize);
//
// Nasty, we have run out of stack space. If
// we can not grow this table then the heap
// will not be able to expand any further.
//
if ( TopOfStack >= MaxStack )
{
//
// Try to grow the stack size.
//
ResizeStack();
//
// Update the pointer as the table may
// have moved.
//
Current = & NewPages[ SizeKey ];
}
//
// We may find ourseleves in a situation where
// the size of the new 'PAGE' structure is larger
// than the natural allocation size or the stack
// is full so we can't create new pages. If so we
// refuse to create any new pages so any allocation
// requests for this size will fail.
//
if ( (TotalPages > 0) && (TopOfStack < MaxStack) )
{
REGISTER CHAR *NewMemory =
((CHAR*) VerifyNewArea( (NaturalSize-1),NaturalSize ));
//
// We may also find ourselves unable to
// anymore memory. If so we will fail the
// request to create a page.
//
if ( NewMemory != AllocationFailure )
{
REGISTER SBIT32 Count;
//
// Add the new allocation to stack of
// outstanding external allocations.
//
Stack[ (TopOfStack ++) ] = ((VOID*) NewMemory);
//
// Add the new elements to the free list
// for the current allocation size.
//
for
(
Count=0;
Count < TotalPages;
Count ++, (NewMemory += FinalSize)
)
{
REGISTER PAGE *Page = ((PAGE*) NewMemory);
//
// The page has been allocated but not
// initialized so call the constructor
// and the destructor to get it into
// a sane state.
//
PLACEMENT_NEW( NewPage,PAGE )
(
NULL,
NULL,
0,
NULL,
0
);
PLACEMENT_DELETE( Page,PAGE );
//
// Finally add the page to the free list
// so it can be used.
//
Page -> InsertInNewPageList( & Current -> FreeList );
}
}
}
}
//
// We are now ready to create a new allocation
// page. We start by requesting a page from
// the parent bucket. If this works we know that
// we have almost everthing we need to create the
// new page.
//
if ( ! Current -> FreeList.EndOfList() )
{
REGISTER VOID *NewMemory;
REGISTER CACHE *ParentPage = (Cache -> GetParentCache());
NewPage = (PAGE::FirstInNewPageList( & Current -> FreeList ));
//
// We have found a suitable page structure
// so remove it from the free list.
//
NewPage -> DeleteFromNewPageList( & Current -> FreeList );
//
// Release any lock we might have as another
// thread may be waiting to delete a page and
// be holding the lock we need in order to
// create a page.
//
ReleaseNewPageLock();
//
// We need to allocate memory to store the users
// data. After all we are the memory allocator
// and that is our job in life. Typically, we do
// this by making a recursive internal request
// from a larger bucket. Nonetheless, at some point
// we will reach the 'TopCache' and will be forced
// to request memory from an external source.
//
if ( (Cache -> TopCache()) || (NewSize != NoSize) )
{
REGISTER AlignMask = (TopCache -> GetPageSize()-1);
//
// We allocate memory externally in large blocks
// and sub-divide these allocations into smaller
// blocks. The only exception is if the caller
// caller is requesting some weird size in which
// case we request memory directly from the
// external allocator (usually the OS).
//
if ( NewSize == NoSize )
{ NewSize = (Cache -> GetPageSize()); }
//
// All externally allocated memory belongs
// to the global root. Thus, it will be
// found in the first lookup in the find
// table.
//
ParentPage = ((CACHE*) GlobalRoot);
//
// Allocate from the external allocator.
//
NewMemory = (VerifyNewArea( AlignMask,NewSize ));
}
else
{
//
// Allocate memory from a larger cache and then
// sub-divide it as needed.
//
NewMemory =
(Cache -> GetParentCache() -> CreateDataPage());
}
//
// Reclaim any lock we have had earlier so
// we can update the the new page structure.
//
ClaimNewPageLock();
//
// Lets make sure we sucessfully allocated the
// memory for the data page.
//
if ( NewMemory != AllocationFailure )
{
//
// We now have everything we need so lets
// create a new page.
//
PLACEMENT_NEW( NewPage,PAGE )
(
NewMemory,
Cache,
NewSize,
ParentPage,
(Version += 2)
);
//
// Finally lets add the new page to the various
// lists so we can quickly find it again later.
//
Cache -> InsertInBucketList( NewPage );
Cache -> InsertInFindList( NewPage );
NewPage -> InsertInNewPageList
(
(Cache -> TopCache())
? & Current -> ExternalList
: & Current -> FullList
);
}
else
{
//
// We were unable to allocate any data space
// for this new page so lets free the page
// description and exit.
//
NewPage -> InsertInNewPageList( & Current -> FreeList );
NewPage = ((PAGE*) AllocationFailure);
}
}
//
// We have finished so release the lock now.
//
ReleaseNewPageLock();
#ifdef DEBUGGING
}
else
{ Failure( "The page size key is out of range" ); }
#endif
return NewPage;
}
/********************************************************************/
/* */
/* Delete all allocations. */
/* */
/* Delete an entire heap and return all the memory to the */
/* top level pool or the external allocator (usually the OS). */
/* */
/********************************************************************/
VOID NEW_PAGE::DeleteAll( BOOLEAN Recycle )
{
REGISTER SBIT32 Count;
//
// Claim the global lock so that the various
// lists can be updated.
//
ClaimNewPageLock();
//
// We assume at this point that we have blocked
// all memory allocation and dealloction requests.
// We are now going to walk through the various lists
// and just blow away things. We are going to
// do this in a tidy way just in case the caller
// wants to use the heap again later.
//
for ( Count=0;Count < MaxNewPages;Count ++ )
{
REGISTER NEW_PAGES *Current = & NewPages[ Count ];
REGISTER PAGE *Page;
REGISTER PAGE *NextPage;
//
// All allocations that appear in the full list
// have been sub-allocated from larger pages in
// almost all cases.
//
for
(
Page = (PAGE::FirstInNewPageList( & Current -> FullList ));
! Page -> EndOfNewPageList();
Page = NextPage
)
{
REGISTER VOID *Address = (Page -> GetAddress());
REGISTER CACHE *Cache = (Page -> GetCache());
REGISTER SBIT32 PageSize = (Page -> GetPageSize());
//
// We decide here how we will deal with the page.
// If it is empty, non-standard or we are not
// recycling we will blow it away. If not we
// simply reset it for later use.
//
if ( (Page -> Empty()) || (PageSize != NoSize) || (! Recycle) )
{
//
// We need to release any associated data page.
// If this is the top level then release the
// memory back to the external allocator. If
// not we release it back to the parent bucket.
//
if ( PageSize == NoSize )
{
//
// If we are just recycling then we cleanly
// delete the page. If not then we know it
// will be blown away later so why bother.
//
if ( Recycle )
{
REGISTER CACHE *ParentCache =
(Cache -> GetParentCache());
if ( ! (ParentCache -> DeleteDataPage( Address )) )
{ Failure( "Reset data page in DeleteAll" ); }
}
}
else
{ Rockall -> DeleteArea( Address,PageSize,True ); }
//
// We may have been blowing away pages
// randomly and now we are about to destroy
// the current page. So lets figure out
// what page comes next before we continue.
//
NextPage = (Page -> NextInNewPageList());
//
// If the page is not full it will in a
// bucket list somewhere. We need to remove
// it as we are about to delete the page.
//
if ( ! Page -> Full() )
{ Cache -> DeleteFromBucketList( Page ); }
//
// Delete the page from the find list and the
// new page list.
//
Cache -> DeleteFromFindList( Page );
Page -> DeleteFromNewPageList( & Current -> FullList );
//
// Delete the page structure.
//
PLACEMENT_DELETE( Page,PAGE );
//
// Finally add the page to the free list
// so it can be recycled.
//
Page -> InsertInNewPageList( & Current -> FreeList );
}
else
{
//
// We know that the current page has at
// least one allocation on it so instead
// of deleting it we will mark it as free
// (except for any sub-allocations) and
// leave it around for next time. If it
// is never used the next top level
// 'DeleteAll' will delete it.
//
Page -> DeleteAll();
//
// We have now reset the current page so
// lets figure out what page comes next.
//
NextPage = (Page -> NextInNewPageList());
}
}
//
// We have a choice to make. If we intend to
// use this heap again we keep all top level
// allocated memory in a list ready for reuse.
// If not we return it to the external allocator
// (usually the OS).
//
if ( ! Recycle )
{
//
// The external allocations list contains an
// entry for every externally allocated page
// except those allocated for special internal
// use within this class or for weird sized
// pages that appeared above in the 'FullList'.
//
for
(
Page = (PAGE::FirstInNewPageList( & Current -> ExternalList ));
! Page -> EndOfNewPageList();
Page = (PAGE::FirstInNewPageList( & Current -> ExternalList ))
)
{
REGISTER VOID *Address = (Page -> GetAddress());
REGISTER CACHE *Cache = (Page -> GetCache());
REGISTER SBIT32 PageSize = (Page -> GetPageSize());
//
// We no longer need this top level allocation
// so return it to the external allocator.
//
Rockall -> DeleteArea( Address,PageSize,True );
//
// If the page is not full it will in a
// bucket list somewhere. We need to remove
// it as we are about to delete the page.
//
if ( ! Page -> Full() )
{ Cache -> DeleteFromBucketList( Page ); }
//
// Delete the page from the find list and the
// new page list.
//
Cache -> DeleteFromFindList( Page );
Page -> DeleteFromNewPageList( & Current -> ExternalList );
//
// Delete the page structure.
//
PLACEMENT_DELETE( Page,PAGE );
//
// Finally add the page to the free list
// so it can be recycled.
//
Page -> InsertInNewPageList( & Current -> FreeList );
}
}
}
//
// We have finished so release the lock now.
//
ReleaseNewPageLock();
}
/********************************************************************/
/* */
/* Delete a page. */
/* */
/* Delete a page structure, free the associated memory and */
/* unlink it from the various allocation lists. */
/* */
/********************************************************************/
VOID NEW_PAGE::DeletePage( PAGE *Page )
{
REGISTER CACHE *Cache = Page -> GetCache();
REGISTER SBIT16 SizeKey = Cache -> GetSizeKey();
//
// All allocations are made from fixed sized
// pages. These pages have a bit vector to
// keep track of which elements are allocated
// and available. The 'SizeKey' is an index
// into 'NewPages[]' that will supply a page
// that has a big enough the bit vector.
//
#ifdef DEBUGGING
if ( (SizeKey >= 0) && (SizeKey < MaxNewPages) )
{
#endif
REGISTER VOID *Address = (Page -> GetAddress());
REGISTER NEW_PAGES *Current = & NewPages[ SizeKey ];
REGISTER SBIT32 Size = (Page -> GetPageSize());
//
// We need to release any associated data page.
// If this is the top level then release the
// memory back to the external allocator. If
// not we release it back to the parent bucket.
//
if ( Size == NoSize )
{
REGISTER CACHE *ParentCache = (Cache -> GetParentCache());
if ( ! (ParentCache -> DeleteDataPage( Address )) )
{ Failure( "Deleting data page in DeletePage" ); }
}
else
{ Rockall -> DeleteArea( Address,Size,True ); }
//
// Claim the global lock so that the various
// lists can be updated.
//
ClaimNewPageLock();
//
// Remove the page from the lists and delete it.
//
Cache -> DeleteFromBucketList( Page );
Cache -> DeleteFromFindList( Page );
Page -> DeleteFromNewPageList
(
(Cache -> TopCache())
? & Current -> ExternalList
: & Current -> FullList
);
PLACEMENT_DELETE( Page,PAGE );
//
// Finally add the page to the free list
// so it can be recycled.
//
Page -> InsertInNewPageList( & Current -> FreeList );
//
// We have finsihed so release the lock.
//
ReleaseNewPageLock();
#ifdef DEBUGGING
}
else
{ Failure( "The page size key out of range in DeletePage" ); }
#endif
}
/********************************************************************/
/* */
/* Find the correct index in new page. */
/* */
/* When we come to create a new page we need to make sure the */
/* bit vector is large enough for the page. We calculate this */
/* here just once to save time later. */
/* */
/********************************************************************/
SBIT16 NEW_PAGE::FindSizeKey( SBIT16 NumberOfElements )
{
REGISTER SBIT32 Count;
//
// Search the table of page structures looking for
// elements of a suitable size. As the table is
// known to be in order of increasing size we can
// terminate the search as soon as we find something
// large enough.
//
for ( Count=0;Count < MaxNewPages;Count ++ )
{
REGISTER NEW_PAGES *Current = & NewPages[ Count ];
if ( NumberOfElements <= Current -> Elements )
{ return ((SBIT16) Count); }
}
//
// Nasty, we don't seem to have anything large enough
// to store the bit vector.
//
return NoSizeKey;
}
/********************************************************************/
/* */
/* Create a new cache stack. */
/* */
/* A cache stack is an array that contains memory allocations */
/* that are waiting to be allocated or released. */
/* */
/********************************************************************/
VOID *NEW_PAGE::NewCacheStack( SBIT32 Size )
{
REGISTER VOID *NewStack;
//
// Claim the global lock so that the various
// lists can be updated.
//
ClaimNewPageLock();
//
// We ensure that there is enough space to make the
// allocation. If not we request additional space
// and prepare it for use.
//
if ( (CacheStack == NULL) || ((MaxCacheStack + Size) > NaturalSize) )
{
//
// Nasty, we have run out of stack space. If
// we can not grow this table then the heap
// will not be able to expand any further.
//
if ( TopOfStack >= MaxStack )
{
//
// Try to grow the stack size.
//
ResizeStack();
}
//
// We may find ourseleves in a situation where
// the size of the new stack structure is larger
// than the natural allocation size or the stack
// is full so we can't create new pages. If so we
// refuse to create any new stacks.
//
if ( (Size < NaturalSize) && (TopOfStack < MaxStack) )
{
REGISTER CHAR *NewMemory =
((CHAR*) VerifyNewArea( (NaturalSize-1),NaturalSize ));
//
// We may also find ourselves unable to
// anymore memory. If so we will fail the
// request to create a new cache stack.
//
if ( NewMemory != AllocationFailure )
{
//
// Add the new allocation to stack of
// outstanding external allocations.
//
Stack[ (TopOfStack ++) ] = ((VOID*) NewMemory);
//
// Prepare the new memory block for use.
//
CacheStack = NewMemory;
MaxCacheStack = 0;
}
else
{ return NULL; }
}
else
{ return NULL; }
}
//
// We allocate some space for the new cache
// stack and update and align the high water
// mark of the space used.
//
NewStack = ((VOID*) & CacheStack[ MaxCacheStack ]);
MaxCacheStack += (Size + CacheLineMask);
MaxCacheStack &= ~CacheLineMask;
//
// We have finished so release the lock now.
//
ReleaseNewPageLock();
return NewStack;
}
/********************************************************************/
/* */
/* Resize the new page stack. */
/* */
/* The new page stack holds pointers to all the pages owned */
/* by the heap. If this stack become full we must expand it */
/* otherwise we can no longer grow the heap. */
/* */
/********************************************************************/
VOID NEW_PAGE::ResizeStack( VOID )
{
REGISTER SBIT32 NewSize =
(((RootStackSize <= 0) ? NaturalSize : RootStackSize) * 2);
//
// Lets just check that we have really run out
// of stack space as expanding it really hurts.
//
if ( TopOfStack >= MaxStack )
{
REGISTER VOID *NewMemory =
(
Rockall -> NewArea
(
(NaturalSize-1),
NewSize,
False
)
);
//
// We need to verify that we were able to allocate
// fresh memory for the stack.
//
if ( NewMemory != NULL )
{
REGISTER BOOLEAN DeleteStack = (RootStackSize > 0);
REGISTER VOID *OriginalMemory = ((VOID*) Stack);
REGISTER SBIT32 OriginalSize = (MaxStack * sizeof(VOID*));
//
// All is well as we were able to allocate
// additional space for the stack. All we
// need to do now is to update the control
// information.
//
MaxStack = (NewSize / sizeof(VOID*));
RootStackSize = NewSize;
Stack = ((VOID**) NewMemory);
//
// Now lets copy across the existing data.
//
memcpy( NewMemory,OriginalMemory,OriginalSize );
//
// When the heap is created we put the
// stack on the root core page. Later
// we may move it if we expand it. If
// this is the case we have to delete
// the previous expansion here.
//
if ( DeleteStack )
{
//
// Deallocate the existing stack if it
// is not on the root core page.
//
Rockall -> DeleteArea( OriginalMemory,OriginalSize,False );
}
}
}
}
/********************************************************************/
/* */
/* Verify an external allocation. */
/* */
/* All memory requests are allocated from the external allocator */
/* at the highest level. Here we have a wrapper for this */
/* function so we can test the result and make sure it is sane. */
/* */
/********************************************************************/
VOID *NEW_PAGE::VerifyNewArea( SBIT32 AlignMask,SBIT32 Size )
{
#ifdef DEBUGGING
//
// We need to ensure that the alignment of the new
// external allocation is a power of two.
//
if ( PowerOfTwo( (AlignMask + 1) ) )
{
#endif
REGISTER VOID *NewMemory =
(Rockall -> NewArea( AlignMask,Size,True ));
//
// We need to ensure that the external allocation
// request is sucessful. If not it makes no sense
// to try and check it.
//
if ( NewMemory != ((VOID*) AllocationFailure) )
{
//
// We require the external memory allocator to always
// allocate memory on the requested boundary. If not
// we are forced to reject the supplied memory.
//
if ( (((SBIT32) NewMemory) & AlignMask) == 0 )
{ return NewMemory; }
else
{
Rockall -> DeleteArea( NewMemory,Size,True );
Failure( "Alignment of allocation in VerifyNewArea" );
}
}
#ifdef DEBUGGING
}
else
{ Failure( "Alignment is not a power of two in VerifyNewArea" ); }
#endif
return ((VOID*) AllocationFailure);
}
/********************************************************************/
/* */
/* 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. */
/* */
/********************************************************************/
BOOLEAN NEW_PAGE::Walk( SEARCH_PAGE *Details )
{
//
// Claim the global lock so that the various
// lists can be updated.
//
ClaimNewPageLock();
//
// We examine the current address to see if it
// is null. If so then this is the start of a
// heap walk so we need to set it up.
//
if ( Details -> Address == NULL )
{
REGISTER SBIT32 Count;
//
// Walk through the list of different sized
// page descriptions.
//
for ( Count=0;Count < MaxNewPages;Count ++ )
{
REGISTER NEW_PAGES *Current = & NewPages[ Count ];
//
// Compute a pointer to the first element
// of the current size.
//
Details -> Page =
(PAGE::FirstInNewPageList( & Current -> FullList ));
//
// Examine the current list of full (or
// partially full) pages. If there is at
// least one page then this is the starting
// point for the heap walk.
//
if ( ! Details -> Page -> EndOfNewPageList() )
{
//
// Compute the starting address of the
// heap walk.
//
Details -> Address =
(Details -> Page -> GetAddress());
break;
}
}
}
else
{
REGISTER PAGE *LastPage = Details -> Page;
//
// We have exhusted the current page so walk
// the list and find the next page.
//
Details -> Page =
(Details -> Page -> NextInNewPageList());
//
// We need to ensure that we have not reached
// the end of the current list.
//
if ( Details -> Page -> EndOfNewPageList() )
{
REGISTER SBIT32 Count;
REGISTER BOOLEAN Found = False;
//
// We need to find a new page description
// list to walk so reset the current
// address just in case we don't find
// anything.
//
Details -> Address = NULL;
//
// We have reached the end of the current
// list and we need to continue with the
// start of the next list. However, we
// don't know which list we were using
// previously. So first we identify the
// previous list and then select the next
// avaibale list.
//
for ( Count=0;Count < MaxNewPages;Count ++ )
{
REGISTER NEW_PAGES *Current = & NewPages[ Count ];
//
// We search for the original list
// we were walking.
//
if ( ! Found )
{
//
// When we find the original list
// then we set a flag showing that
// the next available list is the
// target.
//
if
(
LastPage
==
(PAGE::LastInNewPageList( & Current -> FullList ))
)
{ Found = True; }
}
else
{
//
// We have found the previous list
// so the first element of the next
// list seems a good place to continue.
//
Details -> Page =
(PAGE::FirstInNewPageList( & Current -> FullList ));
//
// We check to make sure that the list
// has at least one active page. If not
// it is worthless and we continue looking
// for a suitable list.
//
if ( ! Details -> Page -> EndOfNewPageList() )
{
//
// Compute the starting address for
// the next page in the heap walk.
//
Details -> Address =
(Details -> Page -> GetAddress());
break;
}
}
}
}
else
{
//
// Compute the starting address for
// the next page in the heap walk.
//
Details -> Address =
(Details -> Page -> GetAddress());
}
}
//
// If we find a new heap page to walk we update
// the details. We mark some entry's as exhusted
// so as to provoke other code to set them up.
//
if ( Details -> Address != NULL )
{
//
// Compute the new allocation details.
//
Details -> Page -> FindPage
(
Details -> Address,
Details,
False
);
}
//
// We have finished so release the lock now.
//
ReleaseNewPageLock();
return (Details -> Address != NULL);
}
/********************************************************************/
/* */
/* Class destructor. */
/* */
/* Destory all the page structures and release any allocated */
/* memory. */
/* */
/********************************************************************/
NEW_PAGE::~NEW_PAGE( VOID )
{
REGISTER SBIT32 Count;
//
// Delete all active allocations.
//
DeleteAll( False );
//
// We are about to delete all of the memory
// allocated by this class so destroy any
// internal pointers.
//
MaxCacheStack = 0;
CacheStack = NULL;
//
// We have now deleted all the memory allocated by
// this heap except for the memory allocated directly
// by this class. Here we finish off the job by
// deleting these allocations and reseting the internal
// data structures.
//
for ( Count=0;Count < TopOfStack;Count ++ )
{
REGISTER VOID *Current = Stack[ Count ];
Rockall -> DeleteArea( Current,NaturalSize,False );
}
TopOfStack = 0;
//
// If we were forced to expand the root stack then
// release this additional memory now.
//
if ( RootStackSize > 0 )
{
//
// Deallocate root stack which previously
// contained pointers to all the memory
// allocated by this class.
//
Rockall -> DeleteArea( ((VOID*) Stack),RootStackSize,False );
}
//
// Delete all the new page list headings just
// to be neat
//
for ( Count=0;Count < MaxNewPages;Count ++ )
{
REGISTER NEW_PAGES *Current = & NewPages[ Count ];
PLACEMENT_DELETE( & Current -> ExternalList,LIST );
PLACEMENT_DELETE( & Current -> FullList,LIST );
PLACEMENT_DELETE( & Current -> FreeList,LIST );
}
//
// Deallocate root core page which previously
// contained all the new page lists.
//
Rockall -> DeleteArea( ((VOID*) NewPages),RootCoreSize,False );
}