home *** CD-ROM | disk | FTP | other *** search
- /*
- File: BestFitH.cpp
-
- Contains: BestFitHeap class implementation
-
- Owned by: Michael Burbidge
-
- Copyright: © 1993 - 1996 by Apple Computer, Inc., all rights reserved.
-
- Change History (most recent first):
-
- <4> 9/13/96 jpa 1371387: Deferred-coalesce optimization.
- Other speedups. 1371387: Sped up BytesFree.
- <3> 6/19/96 jpa 1298260: More consistency checks in
- CheckSegment
- <2> 1/15/96 TJ Cleaned Up
- <14> 8/4/95 DM Leak checking [1267956]
- <13> 5/4/95 jpa Support for finding largest free block
- [1235657] and validating memory ranges
- [1246077]. Better calculation of dflt huge
- block size [1233941]
- <12> 2/14/95 jpa Fixed DoIsValidBlock to do proper size
- checking (was giving spurious warnings.)
- [1215473]
- <11> 12/20/94 jpa Disallow case where fHugeBlockSize >
- sizeIncrement. [1199188]
- <10> 12/5/94 jpa Nuked errant pragma lib_export's. [1195676]
- <9> 10/24/94 jpa Don't call CheckTree all over the place
- unless gValidate>0.
- <8> 9/29/94 RA 1189812: Mods for 68K build.
- <7> 9/14/94 jpa Eliminated dependencies on rest of OpenDoc.
- Added support for getting the heap of a
- block by stuffing heap ptr in busy block
- header. [1186692]
- <6> 8/17/94 jpa Implemented huge-block support [1179565],
- segment disposal [1181509] and the
- SOM-block flag [1181510].
- <5> 8/8/94 jpa Added fHugeBlockSize -- not used yet
- [1179565]
- <4> 8/2/94 jpa Install block cushion hooks. Allocate
- blocks on 4byte boundaries. Fixed bug when
- getting block size (didn't work right with
- hooks installed.)
- <3> 6/18/94 MB Add #pragma lib_export lines
- <2> 6/10/94 MB Make it build
- <1> 6/9/94 MB first checked in
- <5> 5/27/94 MB #1165129: CreateNewSegment doesn't check
- for NULL after allocating new segment.
- <4> 5/27/94 MB #1162181: Fixed MMM integration bug
- <2> 5/9/94 MB #1162181: Changes necessary to install MMM.
- <1> 4/29/94 MB first checked in
-
- To Do:
- In Progress:
-
- */
-
- #ifndef _PLATFMEM_
- #include "PlatfMem.h"
- #endif
-
- #ifndef _MEMMGRPV_
- #include "MemMgrPv.h"
- #endif
-
- #ifndef _BESTFITH_
- #include "BestFitH.h"
- #endif
-
- #if MM_DEBUG
- #ifndef _MEMHOOKS_
- #include "MemHooks.h"
- #endif
- #endif
-
- #ifndef __MEMORY__
- #include <Memory.h>
- #endif
-
- #ifndef __LIMITS__
- #include <limits.h>
- #endif
-
- #ifndef __STRING__
- #include <string.h>
- #endif
-
- #ifndef __STDIO__
- #include <stdio.h>
- #endif
-
-
- #if MM_DEBUG_COALESCE
- static unsigned long gNFastAllocations =0;
- static unsigned long gNSlowAllocations =0;
- static unsigned long gNFastFrees =0;
- static unsigned long gNSlowFrees =0;
- #endif
-
-
- #if MM_DEBUG
- //----------------------------------------------------------------------------------------
- // IsValidBlock
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- static const PrivBestFitBlock *ValidBlock(const void* ptr)
- {
- if( ptr==kMMNULL )
- return kMMNULL;
- if( (long)ptr & 0x00000003 )
- return kMMNULL; // Not on a 4-byte boundary
-
- const PrivBestFitBlock *blk
- = (const PrivBestFitBlock *) ((ODBytePtr) ptr - PrivBestFitBlock::kBusyOverhead);
-
- ODBlockSize blkSize = blk->GetSize();
- if( (blkSize >= PrivBestFitBlock::kMinBlockSize || blkSize <= BestFitBlock_kMaxBlockSize)
- && blk->GetBusy()
- && !blk->GetAvail()
- && blk->GetMagicNumber() == (unsigned int)PrivBestFitBlock::kMagicNumber )
- return blk;
- else
- return kMMNULL;
- }
- #endif
-
-
- #if 0 /* OBSOLETE */
- //----------------------------------------------------------------------------------------
- // PrivBestFitBlock::Coalesce: Coalesce blk with the previous block if both are free.
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- PrivBestFitBlock* PrivBestFitBlock::Coalesce( )
- {
- PrivBestFitBlock * prevBlk = NULL;
-
- if (!this->GetBusy() && !this->GetPrevBusy())
- {
- #if MM_DEBUG
- if (this->GetSize() < PrivBestFitBlock::kMinBlockSize)
- MM_WARN("BestFitHeap::Coalesce: corrupt heap!");
- #endif
-
- prevBlk = this->GetPrevBlock();
- prevBlk->SetSize(prevBlk->GetSize() + this->GetSize());
- prevBlk->StuffAddressAtEnd();
- }
-
- return prevBlk;
- }
- #endif
-
-
- //========================================================================================
- // BestFitHeap
- //========================================================================================
-
- //----------------------------------------------------------------------------------------
- // BestFitHeap::BestFitHeap
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- BestFitHeap::BestFitHeap(unsigned long sizeInitial,
- unsigned long sizeIncrement,
- unsigned long hugeBlockSize, // "0" means sizeIncrement/2
- MMHeapLocation memSrc) :
- MemoryHeap(false, false, false, memSrc)
- {
- #if MM_DEBUG
- CompilerCheck();
- #endif
-
- fSizeIncrement = sizeIncrement;
- fSizeInitial = sizeInitial;
-
- if( hugeBlockSize!=0 )
- fHugeBlockSize = hugeBlockSize;
- else
- fHugeBlockSize = sizeIncrement>>1;
-
- if( fHugeBlockSize > kMaxHugeBlockSize )
- fHugeBlockSize = kMaxHugeBlockSize;
-
- fFreeBytes = fAvailBytes = 0;
- if( fHugeBlockSize > sizeIncrement ) {
- MM_WARN("hugeSize must be <= sizeIncrement");
- fHugeBlockSize = sizeIncrement; // Cannot allow range between huge size & sizeIncrement
- }
-
- fSegments = NULL;
- }
-
- //----------------------------------------------------------------------------------------
- // BestFitHeap::~BestFitHeap
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- BestFitHeap::~BestFitHeap()
- {
- this->DeleteSegments();
- }
-
- //----------------------------------------------------------------------------------------
- // BestFitHeap::IBestFitHeap * MEB *
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- void BestFitHeap::IBestFitHeap()
- {
- this->GrowHeap(fSizeInitial);
-
- #if MM_DEBUG
- ODMemoryHook *hook = new(this->GetLocation()) CBlockStackCrawlHook;
- this->AdoptHook(hook);
- // Block cushion hooks have to be installed before any blocks are allocated
- // in the heap; so do so now if this is a debug build.
- hook = new(this->GetLocation()) CBlockCushionHook;
- this->AdoptHook(hook);
- #endif
- }
-
- //----------------------------------------------------------------------------------------
- // BestFitHeap::ExpandHeap * MEB *
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- void BestFitHeap::ExpandHeap(unsigned long sizeInitial, unsigned long sizeIncrement)
- {
- if (sizeInitial > fSizeInitial)
- fSizeInitial = sizeInitial;
- if (sizeIncrement > fSizeIncrement)
- fSizeIncrement = sizeIncrement;
-
- if (sizeInitial > this->HeapSize())
- this->GrowHeap(sizeInitial);
- else
- this->GrowHeap(sizeIncrement);
- }
-
- //----------------------------------------------------------------------------------------
- // BestFitHeap::AddBytesFree
- //----------------------------------------------------------------------------------------
- #if MM_DEBUG_COALESCE /* In nondebug build this is an inline */
- void BestFitHeap::AddFreeBytes( long n )
- {
- fFreeBytes += n;
- unsigned long bytesFree, numberOfNodes;
- fFreeTree.TreeInfo(bytesFree, numberOfNodes);
- MM_ASSERT(fFreeBytes==bytesFree);
- }
- #endif
-
- #if MM_DEBUG
- //----------------------------------------------------------------------------------------
- // BestFitHeap::Check (MM_DEBUG only)
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- void BestFitHeap::Check( HeapWalkProc proc, void *refCon ) const
- {
- unsigned long bytesFree, numberOfNodes;
- fFreeTree.TreeInfo(bytesFree, numberOfNodes);
- if(fFreeBytes!=bytesFree)
- MM_WARN("Free byte count of %ld doesn't match tree size %ld", fFreeBytes,bytesFree);
-
- ODBlockSize blockHeaderSize = this->CallGetHeaderSize();
- ODBlockSize sizeDelta = this->CallAboutToAllocateHooks(0);
-
- // ----- validate each segment
-
- PrivBestFitSegment * segment;
- for( segment=fSegments; segment != NULL; segment=segment->fNextSegment )
- if( !segment->CheckSegment(proc,refCon,blockHeaderSize,sizeDelta) )
- return;
-
- // ----- check the free tree
-
- fFreeTree.CheckTree();
- }
- #endif
-
- #if MM_DEBUG
- //----------------------------------------------------------------------------------------
- // BestFitHeap::DoFindBlockContaining (MM_DEBUG only)
- //----------------------------------------------------------------------------------------
- mmboolean
- BestFitHeap::DoFindBlockContaining( const void *start, const void* end,
- const void* &blockStart, const void* &blockEnd ) const
- {
- PrivBestFitSegment * segment;
- for( segment=fSegments; segment != NULL; segment=segment->fNextSegment )
- if( segment->FindBlockContaining(start,end, blockStart,blockEnd) )
- return kMMTrue;
- return kMMFalse;
- }
- #endif
-
- //----------------------------------------------------------------------------------------
- // BestFitHeap::DoGetBlockHeap
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- MemoryHeap*
- BestFitHeap::DoGetBlockHeap( const void *block ) const
- {
- #if MM_DEBUG
- if(!ValidBlock(block)) {
- MM_WARN("GetBlockHeap(%p): bogus block",block);
- return kMMNULL;
- }
- #endif
-
- PrivBestFitBlock * blk
- = (PrivBestFitBlock *) ((ODBytePtr) block - PrivBestFitBlock::kBusyOverhead);
-
- BestFitHeap *heap = blk->GetHeap();
- #if MM_DEBUG
- if( !heap->ValidateMagicNumber() )
- return kMMNULL;
- #endif
- return heap;
- }
-
- //----------------------------------------------------------------------------------------
- // BestFitHeap::DoBlockSize
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- ODBlockSize BestFitHeap::DoBlockSize(const void* block) const
- {
- PrivBestFitBlock * blk
- = (PrivBestFitBlock *) ((ODBytePtr) block - PrivBestFitBlock::kBusyOverhead);
-
- #if MM_DEBUG
- MM_ASSERT(blk->GetBusy());
- #endif
-
- return blk->GetSize() - PrivBestFitBlock::kBusyOverhead;
- }
-
- //----------------------------------------------------------------------------------------
- // BestFitHeap::DoAllocate
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- void* BestFitHeap::DoAllocate(ODBlockSize size, ODBlockSize& allocatedSize)
- {
- ODBlockSize blkSize = size + PrivBestFitBlock::kBusyOverhead;
-
- if (blkSize < PrivBestFitBlock::kMinBlockSize)
- blkSize = PrivBestFitBlock::kMinBlockSize;
-
- // Make sure blkSize is a multiple of 4 (to keep all blocks on 4byte boundaries)
- blkSize = (blkSize+3) & ~0x03L;
-
- #if MM_DEBUG
- MM_ASSERT(blkSize <= BestFitBlock_kMaxBlockSize);
- #endif
-
- PrivBestFitBlock * blk;
-
- #ifdef MM_DEFER_COALESCE
- if( blkSize < kAvailBlockSizeLimit+PrivBestFitBlock::kBusyOverhead ) {
- // See if there are blocks on the avail lists for the desired size or larger:
- PrivFreeBlockList *list = &fAvailBlocks[ (blkSize-PrivBestFitBlock::kMinBlockSize) >>2 ];
- for( int i=kNAvailListsToCheck; i>0; i--,list++ )
- if( list->NotEmpty() ) {
- // If so, unhook the block from its list and return it:
- blk = list->GetBlock();
- blk->SetAvail(false);
- blk->SetIsObject(false);
- blk->SetHeap(this);
- ODBlockSize itsSize = blk->GetSize();
- MM_ASSERT(itsSize>=blkSize);
- allocatedSize = itsSize - PrivBestFitBlock::kBusyOverhead;
- fAvailBytes -= itsSize;
- #if MM_DEBUG_COALESCE
- gNFastAllocations++;
- #endif
- return (void *) ((ODBytePtr) blk + PrivBestFitBlock::kBusyOverhead);
- }
- // If not, allocate the block as usual...
- }
- #endif
-
- // A "Huge" block is always allocated its own segment, so the memory can be freed
- // to the platform memory manager as soon as the huge block is deleted:
-
- if( size >= fHugeBlockSize ) {
- blk = this->CreateNewSegment(blkSize + PrivBestFitSegment::kSegmentPrefixSize
- + sizeof(PrivBestFitBlock) );
- if( blk==NULL ) {
- this->Coalesce(); // might dispose a segment...
- blk = this->CreateNewSegment(blkSize + PrivBestFitSegment::kSegmentPrefixSize
- + sizeof(PrivBestFitBlock) );
- }
- if( blk )
- MM_ASSERT(blk->GetSize()==blkSize);
-
- } else {
- // Normal block allocation, searching the free tree:
- blk = this->SearchFreeBlocks(blkSize);
- if( blk != NULL )
- this->RemoveFromFreeBlocks(blk);
- else {
- // Try coalescing avail blocks until we get a big enough free space:
- blk = this->Coalesce(blkSize);
- if (blk == NULL && fSizeIncrement > 0)
- {
- // Finally make an attempt to expand the heap:
- this->GrowHeap(fSizeIncrement);
- blk = this->SearchFreeBlocks(blkSize);
- if( blk != NULL )
- this->RemoveFromFreeBlocks(blk);
- }
- }
- }
-
- if (blk == NULL) {
- allocatedSize = 0;
- return NULL;
- }
-
- #if MM_DEBUG_COALESCE
- gNSlowAllocations++;
- #endif
-
- // We found a block, so mark it busy and remove it from the free list.
-
- blk->SetBusy(true);
- blk->SetHeap(this);
- blk->SetIsObject(false);
-
- ODBlockSize extra = blk->GetSize() - blkSize;
- if (extra >= PrivBestFitBlock::kMinBlockSize) {
- // The block is big enough to split, so here we do the split.
-
- PrivBestFitBlock *newBlk
- = new((void *) ((ODBytePtr) blk + blkSize))
- PrivBestFitBlock(false, true, extra);
- this->AddToFreeBlocks(newBlk);
- blk->SetSize(blkSize);
- } else {
- blk->GetNextBlock()->SetPrevBusy(true);
- }
-
- allocatedSize = blk->GetSize() - PrivBestFitBlock::kBusyOverhead;
- return (void *) ((ODBytePtr) blk + PrivBestFitBlock::kBusyOverhead);
- }
-
- //----------------------------------------------------------------------------------------
- // BestFitHeap::DoFree
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- void BestFitHeap::DoFree(void* ptr)
- {
- PrivBestFitBlock *blk
- = (PrivBestFitBlock *) ((ODBytePtr) ptr - PrivBestFitBlock::kBusyOverhead);
-
- #if MM_DEBUG
- MM_ASSERT(blk->GetBusy());
- #endif
-
- size_t blkSize = blk->GetSize();
-
- #ifdef MM_DEFER_COALESCE
- // If the block is small, just return it to the end of the free list for its size:
- // (reusing blocks in FIFO order greatly reduces fragmentation, say the experts.)
- if( blkSize < kAvailBlockSizeLimit+PrivBestFitBlock::kBusyOverhead ) {
- blk->SetAvail(true);
- long index = (blkSize-PrivBestFitBlock::kMinBlockSize)>>2;
- fAvailBlocks[index].AddBlock(blk);
- fAvailBytes += blkSize;
- #if MM_DEBUG_COALESCE
- gNFastFrees++;
- #endif
- return;
- }
- #endif
-
- // Update block flags and coalesce with free neighbors:
- blk = this->BasicFreeBlock(blk);
-
- // Delete segment if freeing its only block:
- if( blk->GetIsFirst() && this->DeleteSegmentIfEmpty(blk) )
- return;
-
- // If the segment remains, add the free block to the tree:
- this->AddToFreeBlocks(blk);
-
- #if MM_DEBUG_COALESCE
- gNSlowFrees++;
- #endif
- }
-
- //----------------------------------------------------------------------------------------
- // BestFitHeap::BasicFreeBlock: Set block flags & coalesce with free neighbors
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- PrivBestFitBlock*
- BestFitHeap::BasicFreeBlock( PrivBestFitBlock *blk )
- {
- // Free this busy block, coalescing it with free neighbors.
- // Returns new addr of block (may not be same as it may have coalesced with prev block.)
- // Block is *NOT* added to free tree!
-
- MM_ASSERT(blk->GetBusy());
-
- ODBlockSize size = blk->GetSize();
- PrivBestFitBlock *nextBlock = blk->GetNextBlock();
-
- if( !blk->GetPrevBusy() ) {
- // Merge with previous free block:
- blk = blk->GetPrevBlock();
- this->RemoveFromFreeBlocks(blk);
- size += blk->GetSize();
- } else {
- blk->SetBusy(false);
- blk->SetAvail(false);
- }
-
- if( !nextBlock->GetBusy() ) {
- // Merge with next free block:
- this->RemoveFromFreeBlocks(nextBlock);
- size += nextBlock->GetSize();
- } else
- nextBlock->SetPrevBusy(false);
-
- blk->SetSize(size);
- blk->StuffAddressAtEnd();
- return blk;
- }
-
-
- //----------------------------------------------------------------------------------------
- // BestFitHeap::DeleteSegmentIfEmpty: Delete segment if freeing its last block
- //----------------------------------------------------------------------------------------
- mmboolean
- BestFitHeap::DeleteSegmentIfEmpty( PrivBestFitBlock *blk )
- {
- // To be called on the first block in a segment when freeing it:
-
- MM_ASSERT(blk->GetIsFirst());
- MM_ASSERT(!blk->GetBusy());
- // Look just before it for the seg hdr:
- PrivBestFitSegment *segment;
- segment = (PrivBestFitSegment*)( (ODBytePtr)blk - PrivBestFitSegment::kSegmentPrefixSize );
- #if MM_DEBUG
- MM_ASSERT(segment->fSegmentSpace==blk);
- MM_ASSERT(blk->GetSize() + sizeof(PrivBestFitBlock) <= segment->fSegmentSize);
- #endif
- if( blk->GetSize() + sizeof(PrivBestFitBlock) == segment->fSegmentSize ) {
- this->DeleteSegment(segment); // Entire seg is free, so delete it
- return true;
- } else
- return false;
- }
-
- #ifdef MM_DEFER_COALESCE
- //----------------------------------------------------------------------------------------
- // BestFitHeap::Coalesce: Do deferred coalesce of entire heap
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- PrivBestFitBlock* BestFitHeap::Coalesce( ODBlockSize sizeNeeded /*=BestFitBlock_kMaxBlockSize*/ )
- {
- if( fAvailBytes == 0 )
- return NULL; // Nothing to coalesce
- if( sizeNeeded > fFreeBytes+fAvailBytes && sizeNeeded!=BestFitBlock_kMaxBlockSize )
- return NULL; // Not enough room in heap
- // (but BestFitBlock_kMaxBlockSize forces a coalesce anyway)
- PrivFreeBlockList *list;
-
- #if MM_DEBUG_COALESCE
- MM_WARN_COALESCE("Coalescing (need %ld bytes)...", sizeNeeded);
- ODBlockSize freed = 0;
- long nFreed = 0;
- #endif
-
- if( sizeNeeded < kAvailBlockSizeLimit+PrivBestFitBlock::kBusyOverhead ) {
- // If size could be on avail list, check all avail lists for that size & larger.
- // Note that DoAllocate only checks 4 lists larger than the size, so this could
- // succeed where that failed...
- long index = (sizeNeeded-PrivBestFitBlock::kMinBlockSize) >>2;
- list = &fAvailBlocks[index];
- for( int i=kNAvailBlockLists-index; i>0; i--,list++ )
- if( list->NotEmpty() ) {
- // If so, unhook the block from its list and return it:
- PrivBestFitBlock *blk = list->GetBlock();
- MM_ASSERT(blk->GetSize()>=sizeNeeded);
- fAvailBytes -= blk->GetSize();
- blk = this->BasicFreeBlock(blk);
- MM_WARN_COALESCE("...found avail block of size %ld.",blk->GetSize());
- return blk;
- }
- }
-
- list = &fAvailBlocks[kNAvailBlockLists-1]; // start w/large blocks
- for( int i=kNAvailBlockLists-1; i!=0; i--,list-- ) {
- PrivBestFitBlock *next;
- for( PrivBestFitBlock *blk = list->First(); blk; blk = next ) {
- if( MM_DEBUG )
- if( !blk->GetBusy() || !blk->GetAvail()
- || blk->GetMagicNumber() != (unsigned int)PrivBestFitBlock::kMagicNumber )
- MM_WARN("Avail block %p looks bogus",blk);
-
- next = blk->GetNext();
-
- #if MM_DEBUG_COALESCE
- freed += blk->GetSize();
- nFreed++;
- #endif
-
- // Free this block, coalescing it with free neighbors:
- fAvailBytes -= blk->GetSize();
- blk = this->BasicFreeBlock(blk);
- ODBlockSize size = blk->GetSize();
-
- if( size >= sizeNeeded ) {
- list->ForceFirst(next); // Remove blocks we've processed so far
- #if MM_DEBUG_COALESCE
- MM_WARN_COALESCE("...Freed %ld bytes (%ld left) in %ld blocks, created %ld byte free block.",
- freed,fAvailBytes,nFreed,size);
- #endif
- #if MM_DEBUG
- if( gValidate )
- this->Check();
- #endif
- return blk;
- } else if( blk->GetIsFirst() && this->DeleteSegmentIfEmpty(blk) )
- ;
- else
- this->AddToFreeBlocks(blk);
- }
-
- list->ForceEmpty();
- }
-
- #if MM_DEBUG_COALESCE
- MM_WARN_COALESCE("...failed. Freed %ld bytes (%ld left) in %ld blocks.",
- freed,fAvailBytes,nFreed);
- #endif
-
- #if MM_DEBUG
- if( gValidate )
- this->Check();
- #endif
-
- return NULL;
- }
-
-
- /*
- mmboolean BestFitHeap::Coalesce( )
- {
- long n = 0;
-
- // MM_WARN_COALESCE("Coalescing. Freeing small blocks...");
-
- // First mark each small block as unbusy, still without coalescing them:
- PrivFreeBlockList *list = &fAvailBlocks[0];
- for( int i=kNAvailBlockLists-1; i!=0; i--,list++ ) {
- PrivBestFitBlock *next;
- for( PrivBestFitBlock *blk = list->First(); blk; blk = next ) {
- n++;
- next = blk->GetNext();
- blk->SetBusy(false);
- MM_ASSERT(blk->GetAvail()); // Avail will be cleared in segment coalesce
- blk->StuffAddressAtEnd();
- PrivBestFitBlock *nextBlk
- = (PrivBestFitBlock *) ((ODBytePtr) blk + blk->GetSize());
- nextBlk->SetPrevBusy(false);
- }
- list->ForceEmpty();
- }
-
- if( n==0 ) {
- // MM_WARN_COALESCE("...done coalescing, nothing to do.");
- return false; // Nothing happened
- }
-
- // MM_WARN_COALESCE("...Freed %ld small blocks...",n);
-
- // Now walk the entire heap, coalescing sequences of free blocks:
- mmboolean coalescence = false;
- PrivBestFitSegment* *prev = &fSegments;
- PrivBestFitSegment* next;
- for( PrivBestFitSegment *segment=fSegments; segment != NULL; segment=next ) {
- next = segment->fNextSegment;
- if( !segment->Coalesce(this,coalescence) ) {
- this->FreeRawMemory(segment); // segment is empty, dispose it
- *prev = next;
- } else
- prev = &segment->fNextSegment;
- }
-
- #if MM_DEBUG_COALESCE
- this->Check();
- #endif
-
- // MM_WARN_COALESCE("...done coalescing.");
- return coalescence;
- }
- */
- #endif /* MM_DEFER_COALESCE */
-
- //----------------------------------------------------------------------------------------
- // BestFitHeap::DoLargestFreeBlock
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- unsigned long BestFitHeap::DoLargestFreeBlock() const
- {
- const PrivBestFitBlock *blk = fFreeTree.FindLargestBlock();
- if( blk )
- return blk->GetSize() - PrivBestFitBlock::kBusyOverhead;
- else
- return 0;
- }
-
- #if MM_DEBUG
- //----------------------------------------------------------------------------------------
- // BestFitHeap::DoIsValidBlock
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- mmboolean BestFitHeap::DoIsValidBlock(const void* ptr) const
- {
- const PrivBestFitBlock *blk = ValidBlock(ptr);
- if( !blk )
- return kMMFalse;
- else
- // Verify that a huge block must be the first block in its segment:
- return blk->GetIsFirst() || blk->GetSize()<fHugeBlockSize;
- }
- #endif
-
- #if 0
- //----------------------------------------------------------------------------------------
- // BestFitHeap::DoReset
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- void BestFitHeap::DoReset()
- {
- this->DeleteSegments();
- fSegments = NULL;
- fFreeTree = PrivFreeBlockTree();
-
- this->GrowHeap(fSizeInitial);
- }
- #endif
-
- //----------------------------------------------------------------------------------------
- // BestFitHeap::HeapSize
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- unsigned long BestFitHeap::HeapSize() const
- {
- PrivBestFitSegment * segment = fSegments;
- unsigned long heapSize = 0;
-
- while (segment != NULL)
- {
- heapSize += segment->fSegmentSize;
- segment = segment->fNextSegment;
- }
-
- return heapSize;
- }
-
-
- //----------------------------------------------------------------------------------------
- // BestFitHeap::DoSetBlockIsObject
- //----------------------------------------------------------------------------------------
- void BestFitHeap::DoSetBlockIsObject( void* ptr, mmboolean isObject )
- {
- #if MM_DEBUG
- MM_ASSERT(this->DoIsValidBlock(ptr));
- #endif
- PrivBestFitBlock *blk
- = (PrivBestFitBlock *) ((ODBytePtr) ptr - PrivBestFitBlock::kBusyOverhead);
- blk->SetIsObject(isObject);
- }
-
-
-
- //----------------------------------------------------------------------------------------
- // BestFitHeap::DoBlockIsObject
- //----------------------------------------------------------------------------------------
- mmboolean BestFitHeap::DoBlockIsObject( const void* ptr ) const
- {
- #if MM_DEBUG
- MM_ASSERT(this->DoIsValidBlock(ptr));
- #endif
- PrivBestFitBlock *blk
- = (PrivBestFitBlock *) ((ODBytePtr) ptr - PrivBestFitBlock::kBusyOverhead);
- return blk->GetIsObject();
- }
-
-
- #if MM_DEBUG
- //----------------------------------------------------------------------------------------
- // BestFitHeap::IsMyBlock
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- mmboolean BestFitHeap::IsMyBlock(const void* blk) const
- {
- mmboolean myBlock = false;
-
- PrivBestFitSegment * segment = fSegments;
- while (segment != NULL && myBlock == false)
- {
- myBlock = segment->AddressInSegment(blk);
- segment = segment->fNextSegment;
- }
-
- return myBlock;
- }
- #endif
-
- #if MM_DEBUG
- //----------------------------------------------------------------------------------------
- // BestFitHeap::Print
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- void BestFitHeap::Print(char* msg) const
- {
- MM_PRINT("********** BestFitHeap **********\n");
- fFreeTree.PrintTree();
- MM_PRINT("\n");
- }
- #endif
-
- //----------------------------------------------------------------------------------------
- // BestFitHeap::CreateNewSegment
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- PrivBestFitBlock* BestFitHeap::CreateNewSegment(unsigned long size)
- {
- #ifdef BUILD_WIN16
- MM_ASSERT(size < 64L * 1024L);
- #endif
-
- // Make sure size is a multiple of 4 (to keep all blocks on 4byte boundaries)
- size = (size+3) & ~0x03L;
- // For this to work, kSegmentPrefixSize and kSegmentSuffixSize must also be
- // multiples of 4.
-
- mmboolean disposable = (fSegments!=NULL); // First segment is NOT disposable
-
- PrivBestFitSegment * segment
- = (PrivBestFitSegment *)this->AllocateRawMemory((ODBlockSize) size);
-
- if (segment == NULL)
- return NULL;
- else {
- // The actual usable space is offset by the size of the fields
- // of a PrivBestFitSegment.
-
- segment->fSegmentSpace
- = (void *) ((ODBytePtr) segment + PrivBestFitSegment::kSegmentPrefixSize);
- segment->fSegmentSize = size - PrivBestFitSegment::kSegmentPrefixSize;
-
- // Add the segment to the list of segments in this heap.
-
- segment->fNextSegment = fSegments;
- fSegments = segment;
-
- // Suffix the segment with a busy block of zero length so that the last free
- // block is not coalesced with a block past the fEnd of the segment.
-
- void * endOfSegment
- = (void *) ((ODBytePtr) segment->fSegmentSpace + segment->fSegmentSize);
- PrivBestFitBlock *blk
- = new((void *) ((ODBytePtr) endOfSegment - sizeof(PrivBestFitBlock)))
- PrivBestFitBlock(true, false, sizeof(PrivBestFitBlock));
- blk->SetHeap(this);
-
- // Create one free block out of this entire segment and Add it to the
- // free block list.
-
- blk = new(segment->fSegmentSpace)PrivBestFitBlock(false, true, segment->fSegmentSize - sizeof(PrivBestFitBlock));
-
- if( disposable )
- // This is the 1st block (positionally) in the heap, so set its bit:
- blk->SetIsFirst(true);
-
- // Don't add to free blocks (speed optimization for DoAllocate)
-
- MM_WARN_COALESCE("** Created %ld byte segment **",size);
-
- return blk;
- }
- }
-
- //----------------------------------------------------------------------------------------
- // BestFitHeap::DeleteSegment
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- void BestFitHeap::DeleteSegment( PrivBestFitSegment *seg )
- {
- // The segment MUST be empty, and its single free block
- // must already have been removed from the free block tree.
-
- #if MM_DEBUG_COALESCE
- MM_WARN("Deleting a segment.");
- #endif
-
- PrivBestFitSegment *segment = fSegments;
-
- if( segment == seg ) {
- fSegments = seg->fNextSegment;
- this->FreeRawMemory(seg);
- return;
-
- } else
- while (segment != NULL)
- if( segment->fNextSegment == seg ) {
- segment->fNextSegment = seg->fNextSegment;
- this->FreeRawMemory(seg);
- return;
- } else
- segment = segment->fNextSegment;
-
- MM_WARN("Segment not found in list!");
- }
-
- //----------------------------------------------------------------------------------------
- // BestFitHeap::DeleteSegments
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- void BestFitHeap::DeleteSegments()
- {
- PrivBestFitSegment * segment = fSegments;
- while (segment != NULL)
- {
- PrivBestFitSegment * nextSegment = segment->fNextSegment;
- this->FreeRawMemory(segment);
- segment = nextSegment;
- }
- }
-
- //----------------------------------------------------------------------------------------
- // BestFitHeap::GrowHeap
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- void BestFitHeap::GrowHeap(unsigned long sizeIncrement)
- {
- // MM_WARN_COALESCE("Allocating new segment of %ld bytes.",sizeIncrement);
-
- #ifdef BUILD_WIN16
- // To avoid crossing 64K boundries on pointer arithmatic, the size of each segment
- // must be limited to 64K. So a single grow request may result in more than one
- // segment being allocated.
-
- const unsigned long kSegmentSizeLimit = 1024L * 62L; // Allow for 2K overhead
-
- while (sizeIncrement > 0)
- {
- unsigned long segmentSize = sizeIncrement;
- if (segmentSize > kSegmentSizeLimit)
- segmentSize = kSegmentSizeLimit;
- blk = this->CreateNewSegment(segmentSize);
- if( !blk ) return;
- this->AddToFreeBlocks(blk);
- sizeIncrement -= segmentSize;
- }
- #else
- PrivBestFitBlock *blk = this->CreateNewSegment(sizeIncrement);
- if( blk )
- this->AddToFreeBlocks(blk);
- #endif
- }
-
- #if MM_DEBUG
- //----------------------------------------------------------------------------------------
- // BestFitHeap::CompilerCheck
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- void BestFitHeap::CompilerCheck()
- {
- MemoryHeap::CompilerCheck();
-
- char buffer[sizeof(PrivBestFitBlock) + sizeof(void *)];
- PrivBestFitBlock &block = *((PrivBestFitBlock *) buffer);
-
- // Check to make sure the bit field setters and getters work.
-
- // block.SetBlockType(3);
- block.SetBusy(true);
- block.SetPrevBusy(false);
- #ifndef BUILD_WIN16
- block.SetSize(100201);
- #endif
- block.SetMagicNumber(3);
-
- // MM_ASSERT(block.GetBlockType() == 3);
- MM_ASSERT(block.GetBusy() == true);
- MM_ASSERT(block.GetPrevBusy() == false);
- #ifndef BUILD_WIN16
- MM_ASSERT(block.GetSize() == 100201);
- #endif
- MM_ASSERT(block.GetMagicNumber() == 3);
-
- // block.SetBlockType(2);
- block.SetBusy(false);
- block.SetPrevBusy(true);
- block.SetSize(150);
- block.SetMagicNumber(2);
-
- // MM_ASSERT(block.GetBlockType() == 2);
- MM_ASSERT(block.GetBusy() == false);
- MM_ASSERT(block.GetPrevBusy() == true);
- MM_ASSERT(block.GetSize() == 150);
- MM_ASSERT(block.GetMagicNumber() == 2);
- }
- #endif
-
-
- //========================================================================================
- // CLASS PrivFreeBlockTree
- //========================================================================================
-
- //----------------------------------------------------------------------------------------
- // PrivBestFitSegment::CheckSegment
- //----------------------------------------------------------------------------------------
-
- mmboolean PrivBestFitSegment::CheckSegment( HeapWalkProc proc, void *refCon,
- ODBlockSize hdrSize, ODBlockSize sizeDelta )
- {
- PrivBestFitBlock *blk = (PrivBestFitBlock *) fSegmentSpace;
- void *segmentEnd = (char *) fSegmentSpace + fSegmentSize;
- unsigned long blksScanned = 0;
-
- // ----- spin through all the blocks in segment do some consistency checks
-
- while (blk < segmentEnd)
- {
- PrivBestFitBlock *nextBlk;
- MM_ASSERT(blk->GetMagicNumber() == PrivBestFitBlock::kMagicNumber);
- // MM_ASSERT(blk->GetBlockType() == PrivBestFitBlock::kBlockTypeId);
- nextBlk = (PrivBestFitBlock *) ((char *) blk + blk->GetSize());
- if(nextBlk==blk) {
- MM_WARN("Block %p header damaged -- skipping segment",blk);
- return false;
- } else if( nextBlk > segmentEnd ) {
- MM_WARN("Block %p unnaturally large -- skipping segment",blk);
- return false;
- } else if (nextBlk < segmentEnd)
- MM_ASSERT(nextBlk->GetPrevBusy() == blk->GetBusy());
-
- MM_ASSERT(blk->GetAvail()<=blk->GetBusy());
-
- if( proc ) // Call user proc if they supplied one
- if( blk->GetBusy() && !blk->GetAvail() && nextBlk<segmentEnd ) {
- ODBytePtr userBlk = (ODBytePtr)blk + PrivBestFitBlock::kBusyOverhead + hdrSize;
- if( (*proc)((void*)userBlk,
- blk->GetSize()-PrivBestFitBlock::kBusyOverhead-sizeDelta,
- blk->GetIsObject(),
- refCon)
- == false )
- return false; // proc can return false to abort
- }
-
- blksScanned++;
- blk = nextBlk;
- }
-
- // ----- if sizes are valid we should be exactly at the end of the segment
-
- MM_ASSERT(blk == segmentEnd);
- return true;
- }
-
- #if MM_DEBUG
- //----------------------------------------------------------------------------------------
- // PrivBestFitSegment::FindBlockContaining
- //----------------------------------------------------------------------------------------
-
- mmboolean
- PrivBestFitSegment::FindBlockContaining( const void *start, const void* end,
- const void* &blockStart, const void* &blockEnd ) const
- {
- PrivBestFitBlock *blk = (PrivBestFitBlock *) fSegmentSpace;
- void *segmentEnd = (char *) fSegmentSpace + fSegmentSize;
-
- if( end<=blk || start>=segmentEnd )
- return kMMFalse;
- else {
- // Memory range intersects range of this segment:
- while (blk < segmentEnd)
- {
- blockStart = blockEnd = NULL;
- PrivBestFitBlock *nextBlk;
- nextBlk = (PrivBestFitBlock *) ((char *) blk + blk->GetSize());
- if( blk->GetBusy() && nextBlk<segmentEnd ) {
- if( start <= nextBlk ) {
- // The memory range starts before the next block, so return:
- blockStart = (char*)blk + PrivBestFitBlock::kBusyOverhead;
- blockEnd = nextBlk;
- break;
- }
- }
- blk = nextBlk;
- }
- return kMMTrue;
- }
- }
-
- #endif
-
- #if 0 /* OBSOLETE CODE */
- mmboolean
- PrivBestFitSegment::Coalesce( BestFitHeap *heap, mmboolean &coalescence )
- {
- /* Loop through the blocks in the segment.
- When we hit the first free block in a row, we remember its location.
- On subsequent free blocks, remove the previous free block from the free tree.
- When we finally hit a busy block, coalesce the free blocks and add to free tree.
- If there was only one free block in a row, still need to fix it up somewhat
- (stuff address at end and set PrevBusy flag of next block.)
-
- We can tell newly freed small blocks because their Avail flag is true.
- They don't need to be removed from the free list 'cause they're not on it.
-
- If there are no busy blocks left in this segment, don't add the humongous
- single free block back to the free tree; instead return false so that the
- caller (BestFitHeap::Coalesce()) will know to dispose this segment. */
-
- PrivBestFitBlock *blk = (PrivBestFitBlock *) fSegmentSpace;
- void *segmentEnd = (char *) fSegmentSpace + fSegmentSize;
-
- PrivBestFitBlock *co = NULL; // First free block in a row
- PrivBestFitBlock *prevBlk = NULL;
-
- #if MM_DEBUG_COALESCE
- long nBlocks =1;
- #endif
-
- // Remember that the last block is a fake busy block, which is just what we want.
-
- while( blk < segmentEnd ) {
- PrivBestFitBlock *nextBlk = (PrivBestFitBlock *) ((char *) blk + blk->GetSize());
-
- if( !blk->GetBusy() ) {
- if( !co )
- co = blk;
- else {
- if( !prevBlk->GetAvail() )
- heap->RemoveFromFreeBlocks(prevBlk);
- #if MM_DEBUG_COALESCE
- nBlocks++;
- #endif
- }
- } else {
- if( co ) {
- if( co!=prevBlk ) {
- // End of a string of free blocks:
- // MM_WARN_COALESCE(" coalescing range %p -- %p (%d blocks)", co,blk,nBlocks);
- if( !prevBlk->GetAvail() )
- heap->RemoveFromFreeBlocks(prevBlk);
- if( co==(PrivBestFitBlock*)fSegmentSpace && nextBlk==segmentEnd )
- return false; // entire segment is now free
- co->SetSize((size_t)blk-(size_t)co);
- co->SetAvail(false);
- co->StuffAddressAtEnd();
- heap->AddToFreeBlocks(co);
- coalescence = true; // something did get coalesced
- } else if( co->GetAvail() ) {
- // Single newly-free block:
- co->SetAvail(false);
- heap->AddToFreeBlocks(co);
- }
- co = NULL;
- #if MM_DEBUG_COALESCE
- nBlocks = 1;
- #endif
- }
- }
-
- prevBlk = blk;
- blk = nextBlk;
- }
-
- return true;
- }
- #endif /* END OBSOLETE CODE */
-
-
- //========================================================================================
- // CLASS PrivFreeBlockTree
- //========================================================================================
-
- //----------------------------------------------------------------------------------------
- // PrivFreeBlockTree::PrivFreeBlockTree
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- PrivFreeBlockTree::PrivFreeBlockTree() :
- fRoot(true, true, 0)
- {
- fRoot.SetRight(NULL);
- fRoot.SetLeft(NULL);
- fRoot.SetParent(NULL);
- }
-
- //----------------------------------------------------------------------------------------
- // PrivFreeBlockTree::PrivFreeBlockTree
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- PrivFreeBlockTree::PrivFreeBlockTree(const PrivFreeBlockTree& blk) :
- fRoot(blk.fRoot)
- {
- }
-
- //----------------------------------------------------------------------------------------
- // PrivFreeBlockTree::AddBlock
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- void PrivFreeBlockTree::AddBlock(PrivBestFitBlock* blk)
- {
- #if MM_DEBUG
- if( gValidate>0 )
- this->CheckTree();
-
- #ifdef OD_INTENSE_DEBUG
- MM_PRINT("PrivFreeBlockTree::AddBlock Entry-------------------------------------\n");
- this->PrintTree();
- #endif
- #endif
-
- PrivBestFitBlock * parent;
-
- this->SearchForBlock(blk->GetSize(), blk, &parent);
-
- blk->SetRight(NULL);
- blk->SetLeft(NULL);
- blk->SetParent(parent);
-
- if (*blk > *parent)
- parent->SetRight(blk);
- else
- parent->SetLeft(blk);
-
- #if MM_DEBUG
- if( gValidate>0 )
- this->CheckTree();
-
- #ifdef OD_INTENSE_DEBUG
- MM_PRINT("PrivFreeBlockTree::AddBlock Exit\n");
- this->PrintTree();
- MM_PRINT("\n");
- #endif
- #endif
- }
-
- #if MM_DEBUG
- //----------------------------------------------------------------------------------------
- // PrivFreeBlockTree::CheckTree
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- void PrivFreeBlockTree::CheckTree() const
- {
- this->CheckTreeHelper(&((PrivFreeBlockTree *)this)->fRoot);
- }
- #endif
-
- #if MM_DEBUG
- //----------------------------------------------------------------------------------------
- // PrivFreeBlockTree::PrintTree
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- void PrivFreeBlockTree::PrintTree() const
- {
- this->PrintTreeHelper(&((PrivFreeBlockTree *)this)->fRoot);
- }
- #endif
-
- //----------------------------------------------------------------------------------------
- // PrivFreeBlockTree::RemoveBlock
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- void PrivFreeBlockTree::RemoveBlock(PrivBestFitBlock* blk)
- {
- #if MM_DEBUG
- if( gValidate > 0 )
- this->CheckTree();
-
- #ifdef OD_INTENSE_DEBUG
- MM_PRINT("PrivFreeBlockTree::RemoveBlock Entry----------------------------------\n");
- this->PrintTree();
- #endif
- #endif
-
- PrivBestFitBlock * spliceOutBlk;
-
- // Decide which block to splice out of the tree. Either the block being
- // removed, or its successor block in the tree.
-
- if (blk->GetLeft() == NULL || blk->GetRight() == NULL)
- spliceOutBlk = blk;
- else
- spliceOutBlk = this->GetSuccessorBlk(blk);
-
- // Splice the node out of the tree
-
- PrivBestFitBlock * tmp;
- PrivBestFitBlock * parent = spliceOutBlk->GetParent();
- if (spliceOutBlk->GetLeft())
- tmp = spliceOutBlk->GetLeft();
- else
- tmp = spliceOutBlk->GetRight();
- if (tmp)
- tmp->SetParent(parent);
- if (spliceOutBlk == parent->GetLeft())
- parent->SetLeft(tmp);
- else
- parent->SetRight(tmp);
-
- // If we spliced out the successor to blk above then we need to patch the successor
- // back in, in Place of blk.
-
- if (spliceOutBlk != blk)
- {
- PrivBestFitBlock * parent = blk->GetParent();
-
- // Fix up the parent's child pointer.
-
- if (parent->GetLeft() == blk)
- parent->SetLeft(spliceOutBlk);
- else
- parent->SetRight(spliceOutBlk);
-
- // Fix up the splice in block's pointers.
-
- spliceOutBlk->SetParent(parent);
- spliceOutBlk->SetLeft(blk->GetLeft());
- spliceOutBlk->SetRight(blk->GetRight());
-
- // Fix up the children of the splice in block's parent pointers.
-
- if (spliceOutBlk->GetLeft())
- (spliceOutBlk->GetLeft())->SetParent(spliceOutBlk);
- if (spliceOutBlk->GetRight())
- (spliceOutBlk->GetRight())->SetParent(spliceOutBlk);
- }
-
- #if MM_DEBUG
- if( gValidate>0 )
- this->CheckTree();
-
- #ifdef OD_INTENSE_DEBUG
- MM_PRINT("PrivFreeBlockTree::RemoveBlock Exit\n");
- this->PrintTree();
- MM_PRINT("\n");
- #endif
- #endif
- }
-
- //----------------------------------------------------------------------------------------
- // PrivFreeBlockTree::SearchForBlock
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- PrivBestFitBlock* PrivFreeBlockTree::SearchForBlock(ODBlockSize size,
- void* blk,
- PrivBestFitBlock** insertLeaf)
- {
- #if MM_DEBUG
- if( gValidate>0 )
- this->CheckTree();
-
- #ifdef OD_INTENSE_DEBUG
- char str[80];
- sprintf(str, "PrivFreeBlockTree::SearchForBlock(%d)---------------------------------\n", size);
- MM_PRINT(str);
- this->PrintTree();
- #endif
- #endif
-
- long minDiff = LONG_MAX;
- PrivBestFitBlock * minDiffBlock = NULL;
- PrivBestFitBlock * currentBlock = &fRoot;
- PrivBestFitBlock * lastBlock;
- do
- {
- lastBlock = currentBlock;
- long diff = currentBlock->GetSize() - size;
- if (diff >= 0 && diff <= minDiff)
- {
- minDiffBlock = currentBlock;
- minDiff = diff;
- }
-
- // Determine which branch of the tree to continue down. Since duplicate keys are
- // difficult to deal with in binary trees, we use the address of blocks to break
- // ties, in the case of two blocks whose size are equal.
-
- if ( diff>0 )
- currentBlock = currentBlock->GetLeft();
- else if ( diff<0 )
- currentBlock = currentBlock->GetRight();
- else if (blk)
- {
- if (blk <= currentBlock)
- currentBlock = currentBlock->GetLeft();
- else
- currentBlock = currentBlock->GetRight();
- }
- else
- currentBlock = currentBlock->GetLeft();
-
- } while (currentBlock != NULL);
-
- if (insertLeaf)
- *insertLeaf = lastBlock;
-
- return minDiffBlock;
- }
-
- //----------------------------------------------------------------------------------------
- // PrivFreeBlockTree::FindLargestBlock
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- const PrivBestFitBlock* PrivFreeBlockTree::FindLargestBlock( ) const
- {
- // The block to the right in the tree is always larger...
-
- const PrivBestFitBlock * currentBlock = &fRoot;
- const PrivBestFitBlock * nextBlock;
- while( (nextBlock = currentBlock->GetRight()) != kMMNULL )
- currentBlock = nextBlock;
- return currentBlock;
- }
-
- //----------------------------------------------------------------------------------------
- // PrivFreeBlockTree::TreeInfo
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- void PrivFreeBlockTree::TreeInfo(unsigned long& bytesFree,
- unsigned long& numberOfNodes) const
- {
- bytesFree = numberOfNodes = 0;
- this->TreeInfoHelper(&((PrivFreeBlockTree *)this)->fRoot, bytesFree, numberOfNodes);
-
- // Subtract one from the number of nodes to account for the header node which
- // is always empty.
-
- numberOfNodes--;
- }
-
- #if MM_DEBUG
- //----------------------------------------------------------------------------------------
- // PrivFreeBlockTree::CheckTreeHelper
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- void PrivFreeBlockTree::CheckTreeHelper(PrivBestFitBlock* blk) const
- {
- if (blk == NULL)
- return;
-
- this->CheckTreeHelper(blk->GetLeft());
-
- PrivBestFitBlock * parent = blk->GetParent();
- if (parent != NULL)
- {
- if (parent->GetRight() == blk)
- {
- if (*blk < *parent)
- {
- this->PrintTree();
- MM_WARN("PrivFreeBlockTree::CheckTreeHelper"
- "Corrupt free list tree: "
- "right child less than parent.");
- }
- }
- else if (parent->GetLeft() == blk)
- {
- if (*blk > *parent)
- {
- MM_WARN("PrivFreeBlockTree::CheckTreeHelper"
- "Corrupt free list tree: "
- "left child greater than parent.");
- }
- }
- else
- {
- MM_WARN("PrivFreeBlockTree::CheckTreeHelper"
- "Corrupt free list tree: "
- "I am not my parent's child.");
- }
- }
- }
- #endif
-
- //----------------------------------------------------------------------------------------
- // PrivFreeBlockTree::GetSuccessorBlk
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- PrivBestFitBlock* PrivFreeBlockTree::GetSuccessorBlk(PrivBestFitBlock* blk)
- {
- PrivBestFitBlock * current = blk->GetRight();
- if (current)
- {
- PrivBestFitBlock *left;
- while( (left=current->GetLeft()) != NULL )
- current = left;
- return current;
- }
- else
- {
- PrivBestFitBlock * parent = blk->GetParent();
- while (parent != NULL && current == parent->GetRight())
- {
- current = parent;
- parent = parent->GetParent();
- }
- return parent;
- }
- }
-
- #if MM_DEBUG
- //----------------------------------------------------------------------------------------
- // PrivFreeBlockTree::PrintTreeHelper
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- void PrivFreeBlockTree::PrintTreeHelper(PrivBestFitBlock* blk,
- int level) const
- {
- for (int i = 0; i < level; i++)
- MM_PRINT("\t");
-
- if (blk == NULL)
- {
- MM_PRINT("NULL\n");
- return;
- }
-
- char str[80];
- //sprintf(str, "Block=%lx fSize=%ld\n", blk, blk->GetSize());
- MM_PRINT(str);
-
- this->PrintTreeHelper(blk->GetLeft(), level + 1);
- this->PrintTreeHelper(blk->GetRight(), level + 1);
- }
- #endif
-
- //----------------------------------------------------------------------------------------
- // PrivFreeBlockTree::TreeInfoHelper
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- void PrivFreeBlockTree::TreeInfoHelper(PrivBestFitBlock* blk,
- unsigned long& bytesFree,
- unsigned long& numberOfNodes) const
- {
- if (blk == NULL)
- return;
-
- this->TreeInfoHelper(blk->GetLeft(), bytesFree, numberOfNodes);
-
- numberOfNodes++;
- bytesFree += blk->GetSize();
-
- this->TreeInfoHelper(blk->GetRight(), bytesFree, numberOfNodes);
- }
-