// 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 ); }