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):
-
- <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
-
-
- #define BLOCKS_ON_4BYTE 1 // Allocate blocks on 4-byte boundaries.
-
-
- #if MM_DEBUG
- //----------------------------------------------------------------------------------------
- // IsValidBlock
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- static const PrivBestFitBlock *ValidBlock(const void* ptr)
- {
- if( ptr==kMMNULL )
- return kMMNULL;
- #if BLOCKS_ON_4BYTE
- if( (long)ptr & 0x00000003 )
- return kMMNULL; // Not on a 4-byte boundary
- #endif
-
- const PrivBestFitBlock *blk
- = (const PrivBestFitBlock *) ((ODBytePtr) ptr - PrivBestFitBlock::kBusyOverhead);
-
- ODBlockSize blkSize = blk->GetSize();
- if( (blkSize >= PrivBestFitBlock::kMinBlockSize || blkSize <= BestFitBlock_kMaxBlockSize)
- && blk->GetBusy()
- && blk->GetMagicNumber() == (unsigned int)PrivBestFitBlock::kMagicNumber )
- return blk;
- else
- return kMMNULL;
- }
- #endif
-
- //========================================================================================
- // PrivBestFitBlock
- //========================================================================================
-
- //----------------------------------------------------------------------------------------
- // PrivBestFitBlock::operator >
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- Boolean PrivBestFitBlock::operator>(const PrivBestFitBlock& blk) const
- {
- if (GetSize() == blk.GetSize())
- return this > &blk;
- else
- return GetSize() > blk.GetSize();
- }
-
- //----------------------------------------------------------------------------------------
- // PrivBestFitBlock::operator <
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- Boolean PrivBestFitBlock::operator<(const PrivBestFitBlock& blk) const
- {
- if (GetSize() == blk.GetSize())
- return this < &blk;
- else
- return GetSize() < blk.GetSize();
- }
-
- //----------------------------------------------------------------------------------------
- // PrivBestFitBlock::operator ==
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- Boolean PrivBestFitBlock::operator==(const PrivBestFitBlock& blk) const
- {
- return GetSize() == blk.GetSize() && this == &blk;
- }
-
- //----------------------------------------------------------------------------------------
- // PrivBestFitBlock::StuffAddressAtEnd
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- void PrivBestFitBlock::StuffAddressAtEnd()
- {
- // coalescence possible in constant time.
-
- if (!this->GetBusy())
- {
- void** addr= (void**) ((ODBytePtr) this + this->GetSize() - sizeof(PrivBestFitBlock *));
- *addr = this;
- }
- #if MM_DEBUG
- else
- MM_WARN("PrivBestFitBlock::StuffAddressAtEnd: corrupt heap!");
- #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;
-
- if( fHugeBlockSize > sizeIncrement ) {
- MM_WARN("hugeSize must be <= sizeIncrement");
- fHugeBlockSize = sizeIncrement; // Cannot allow range between huge size & sizeIncrement
- }
-
- fSegments = NULL;
-
- // this->GrowHeap(fSizeInitial); * MEB *
- }
-
- //----------------------------------------------------------------------------------------
- // 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::BytesFree
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- unsigned long BestFitHeap::BytesFree() const
- {
- unsigned long bytesFree, numberOfNodes;
-
- fFreeTree.TreeInfo(bytesFree, numberOfNodes);
- bytesFree -= numberOfNodes * PrivBestFitBlock::kBusyOverhead;
-
- return bytesFree;
- }
-
- #if MM_DEBUG
- //----------------------------------------------------------------------------------------
- // BestFitHeap::Check (MM_DEBUG only)
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- void BestFitHeap::Check( HeapWalkProc proc, void *refCon ) const
- {
- ODBlockSize blockHeaderSize = this->CallGetHeaderSize();
-
- // ----- validate each segment
-
- PrivBestFitSegment * segment;
- for( segment=fSegments; segment != NULL; segment=segment->fNextSegment )
- if( !segment->CheckSegment(proc,refCon,blockHeaderSize) )
- 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::DoAllocate
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- void* BestFitHeap::DoAllocate(ODBlockSize size, ODBlockSize& allocatedSize)
- {
- ODBlockSize blkSize = size + PrivBestFitBlock::kBusyOverhead;
-
- if (blkSize < PrivBestFitBlock::kMinBlockSize)
- blkSize = PrivBestFitBlock::kMinBlockSize;
-
- #if BLOCKS_ON_4BYTE
- // Make sure blkSize is a multiple of 4 (to keep all blocks on 4byte boundaries)
- // (Added this fix on 7/28/94 on Mike's advice. --jpa)
- blkSize = (blkSize+3) & ~0x03L;
- #else
- // Make sure blkSize is even
- if (blkSize & 0x01)
- blkSize++;
- #endif
-
- #if MM_DEBUG
- MM_ASSERT(blkSize <= BestFitBlock_kMaxBlockSize);
- #endif
-
- PrivBestFitBlock * blk;
-
- // 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 )
- MM_ASSERT(blk->GetSize()==blkSize);
-
- } else {
- blk = this->SearchFreeBlocks(blkSize); // Not huge, so search free blocks
- if (blk == NULL && fSizeIncrement > 0)
- {
- this->GrowHeap(fSizeIncrement); // Make an attempt to expand the heap
- blk = this->SearchFreeBlocks(blkSize);
- }
- }
-
- allocatedSize = 0;
- void* newPtr = NULL;
-
- if (blk != NULL)
- {
- // We found a block, so mark it busy and remove it from the free list.
-
- blk->SetBusy(true);
- this->RemoveFromFreeBlocks(blk);
- blk->SetHeap(this);
- blk->SetIsObject(false);
-
- if (blk->GetSize() - blkSize >= 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, blk->GetSize() - blkSize);
- this->AddToFreeBlocks(newBlk);
- blk->SetSize(blkSize);
- }
-
- PrivBestFitBlock * nextBlk
- = (PrivBestFitBlock *) ((ODBytePtr) blk + blk->GetSize());
- nextBlk->SetPrevBusy(true);
-
- newPtr = (void *) ((ODBytePtr) blk + PrivBestFitBlock::kBusyOverhead);
- allocatedSize = blk->GetSize() - PrivBestFitBlock::kBusyOverhead;
- }
-
- return newPtr;
- }
-
- //----------------------------------------------------------------------------------------
- // 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::DoFree
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- void BestFitHeap::DoFree(void* ptr)
- {
- PrivBestFitBlock *blk
- = (PrivBestFitBlock *) ((ODBytePtr) ptr - PrivBestFitBlock::kBusyOverhead);
-
- #if MM_DEBUG
- MM_ASSERT(blk->GetBusy());
- #endif
-
- blk->SetBusy(false);
- blk->StuffAddressAtEnd();
-
- PrivBestFitBlock *nextBlk
- = (PrivBestFitBlock *) ((ODBytePtr) blk + blk->GetSize());
- nextBlk->SetPrevBusy(false);
-
- if (this->Coalesce(nextBlk))
- this->RemoveFromFreeBlocks(nextBlk);
-
- PrivBestFitBlock * prevBlk = this->Coalesce(blk);
- if (prevBlk)
- {
- this->RemoveFromFreeBlocks(prevBlk);
- //this->AddToFreeBlocks(prevBlk);// Nope, now happens down below unless seg is freed --jpa
- blk = prevBlk;
- }
-
- if( blk->GetIsFirst() ) {
- // If the first block of the segment is free, 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;
- }
- }
-
- // If the segment remains, add the free block to the tree:
- this->AddToFreeBlocks(blk);
- }
-
- //----------------------------------------------------------------------------------------
- // 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
-
- Boolean 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
-
- //----------------------------------------------------------------------------------------
- // BestFitHeap::DoReset
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- void BestFitHeap::DoReset()
- {
- this->DeleteSegments();
- fSegments = NULL;
- fFreeTree = PrivFreeBlockTree();
-
- this->GrowHeap(fSizeInitial);
- }
-
- //----------------------------------------------------------------------------------------
- // 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, Boolean isObject )
- {
- #if MM_DEBUG
- MM_ASSERT(this->DoIsValidBlock(ptr));
- #endif
- PrivBestFitBlock *blk
- = (PrivBestFitBlock *) ((ODBytePtr) ptr - PrivBestFitBlock::kBusyOverhead);
- blk->SetIsObject(isObject);
- }
-
-
-
- //----------------------------------------------------------------------------------------
- // BestFitHeap::DoBlockIsObject
- //----------------------------------------------------------------------------------------
- Boolean 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
-
- Boolean BestFitHeap::IsMyBlock(const void* blk) const
- {
- Boolean 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::AddToFreeBlocks
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- void BestFitHeap::AddToFreeBlocks(PrivBestFitBlock* blk)
- {
- fFreeTree.AddBlock(blk);
- }
-
- //----------------------------------------------------------------------------------------
- // BestFitHeap::Coalesce: Coalesce blk with the previous block if both are free.
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- PrivBestFitBlock* BestFitHeap::Coalesce(PrivBestFitBlock* blk)
- {
- PrivBestFitBlock * prevBlk = NULL;
-
- if (!blk->GetBusy() && !blk->GetPreviousBusy())
- {
- #if MM_DEBUG
- if (blk->GetSize() < PrivBestFitBlock::kMinBlockSize)
- MM_WARN("BestFitHeap::Coalesce: corrupt heap!");
- #endif
-
- prevBlk = *(PrivBestFitBlock **) ((ODBytePtr) blk - sizeof(ODBlockSize));
- prevBlk->SetSize(prevBlk->GetSize() + blk->GetSize());
- prevBlk->StuffAddressAtEnd();
- }
-
- return prevBlk;
- }
-
- //----------------------------------------------------------------------------------------
- // BestFitHeap::CreateNewSegment
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- PrivBestFitBlock* BestFitHeap::CreateNewSegment(unsigned long size)
- {
- #ifdef BUILD_WIN16
- MM_ASSERT(size < 64L * 1024L);
- #endif
-
- #if BLOCKS_ON_4BYTE
- // Make sure size is a multiple of 4 (to keep all blocks on 4byte boundaries)
- // (Added this fix on 7/28/94 on Mike's advice. --jpa)
- size = (size+3) & ~0x03L;
- // For this to work, kSegmentPrefixSize and kSegmentSuffixSize must also be
- // multiples of 4.
- #else
- // Make sure segment size is even
- if (size & 0x01)
- size++;
- #endif
-
- Boolean 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: --jpa
- blk->SetIsFirst(true);
-
- this->AddToFreeBlocks(blk);
-
- 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. --jpa
-
- 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)
- {
- #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;
- this->CreateNewSegment(segmentSize);
- sizeIncrement -= segmentSize;
- }
- #else
- this->CreateNewSegment(sizeIncrement);
- #endif
- }
-
- //----------------------------------------------------------------------------------------
- // BestFitHeap::RemoveFromFreeBlocks
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- void BestFitHeap::RemoveFromFreeBlocks(PrivBestFitBlock* blk)
- {
- fFreeTree.RemoveBlock(blk);
- }
-
- //----------------------------------------------------------------------------------------
- // BestFitHeap::SearchFreeBlocks
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- PrivBestFitBlock* BestFitHeap::SearchFreeBlocks(ODBlockSize size)
- {
- //all blocks are of even length, so round up to fNext even number
-
- if (size & 1)
- size++;
-
- return fFreeTree.SearchForBlock(size, NULL, NULL);
- }
-
- #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.GetPreviousBusy() == 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.GetPreviousBusy() == true);
- MM_ASSERT(block.GetSize() == 150);
- MM_ASSERT(block.GetMagicNumber() == 2);
- }
- #endif
-
-
- //========================================================================================
- // CLASS PrivFreeBlockTree
- //========================================================================================
-
- //----------------------------------------------------------------------------------------
- // PrivBestFitSegment::CheckSegment
- //----------------------------------------------------------------------------------------
-
- Boolean PrivBestFitSegment::CheckSegment( HeapWalkProc proc, void *refCon, ODBlockSize hdrSize )
- {
- 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 < segmentEnd)
- MM_ASSERT(nextBlk->GetPreviousBusy() == blk->GetBusy());
-
- if( proc ) // Call user proc if they supplied one
- if( blk->GetBusy() && nextBlk<segmentEnd ) {
- ODBytePtr userBlk = (ODBytePtr)blk + PrivBestFitBlock::kBusyOverhead + hdrSize;
- if( (*proc)((void*)userBlk, blk->GetSize()-hdrSize, 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
-
-
- //========================================================================================
- // CLASS PrivFreeBlockTree
- //========================================================================================
-
- //----------------------------------------------------------------------------------------
- // PrivFreeBlockTree::PrivFreeBlockTree
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- PrivFreeBlockTree::PrivFreeBlockTree() :
- fRoot(true, true, 0)
- {
- fRoot.SetRight(NULL);
- fRoot.SetLeft(NULL);
- }
-
- //----------------------------------------------------------------------------------------
- // PrivFreeBlockTree::PrivFreeBlockTree
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- PrivFreeBlockTree::PrivFreeBlockTree(const PrivFreeBlockTree& blk) :
- fRoot(blk.fRoot)
- {
- }
-
- //----------------------------------------------------------------------------------------
- // PrivFreeBlockTree::operator=
- //----------------------------------------------------------------------------------------
- #pragma segment HeapSeg
-
- PrivFreeBlockTree& PrivFreeBlockTree::operator=(const PrivFreeBlockTree& blk)
- {
- fRoot = blk.fRoot;
- return (*this);
- }
-
- //----------------------------------------------------------------------------------------
- // 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;
- do
- {
- long diff = currentBlock->GetSize() - size;
- if (diff >= 0 && diff < minDiff)
- {
- minDiffBlock = currentBlock;
- minDiff = diff;
- }
-
- if (insertLeaf)
- *insertLeaf = currentBlock;
-
- // 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 (size < currentBlock->GetSize())
- currentBlock = currentBlock->GetLeft();
- else if (size > currentBlock->GetSize())
- currentBlock = currentBlock->GetRight();
- else if (blk)
- {
- if (blk <= currentBlock)
- currentBlock = currentBlock->GetLeft();
- else
- currentBlock = currentBlock->GetRight();
- }
- else
- currentBlock = currentBlock->GetLeft();
-
- } while (currentBlock != NULL);
-
- 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)
- {
- if (blk->GetRight())
- {
- PrivBestFitBlock * current = blk->GetRight();
- while (current->GetLeft())
- current = current->GetLeft();
- return current;
- }
- else
- {
- PrivBestFitBlock * parent = blk->GetParent();
- PrivBestFitBlock * current = NULL;
- 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);
- }
-