Esempio n. 1
0
// SanityCheck
bool
BlockAllocator::Area::SanityCheck() const
{
	// area ID
	if (fID < 0) {
		FATAL(("Area ID < 0: %lx\n", fID));
		BA_PANIC("Bad area ID.");
		return false;
	}
	// size
	size_t areaHeaderSize = block_align_ceil(sizeof(Area));
	if (fSize < areaHeaderSize + sizeof(TFreeBlock)) {
		FATAL(("Area too small to contain area header and at least one free "
			   "block: %lu bytes\n", fSize));
		BA_PANIC("Bad area size.");
		return false;
	}
	// free bytes
	if (fFreeBytes > fSize) {
		FATAL(("Free size greater than area size: %lu vs %lu\n", fFreeBytes,
			   fSize));
		BA_PANIC("Bad area free bytes.");
		return false;
	}
	// block count
	if (fFreeBlockCount + fUsedBlockCount == 0) {
		FATAL(("Area contains no blocks at all.\n"));
		BA_PANIC("Bad area block count.");
		return false;
	}
	// block list
	uint32 usedBlockCount = 0;
	uint32 freeBlockCount = 0;
	size_t freeBytes = 0;
	if (!fFirstBlock || !fLastBlock) {
		FATAL(("Invalid block list: first or last block NULL: first: %p, "
			   "last: %p\n", fFirstBlock, fLastBlock));
		BA_PANIC("Bad area block list.");
		return false;
	} else {
		// iterate through block list and also check free list
		int32 blockCount = fFreeBlockCount + fUsedBlockCount;
		Block *block = fFirstBlock;
		Block *prevBlock = NULL;
		Block *prevFree = NULL;
		Block *nextFree = fFirstFree;
		bool blockListOK = true;
		for (int32 i = 0; i < blockCount; i++) {
			blockListOK = false;
			if (!block) {
				FATAL(("Encountered NULL in block list at index %ld, although "
					   "list should have %ld blocks\n", i, blockCount));
				BA_PANIC("Bad area block list.");
				return false;
			}
			uint64 address = (uint32)block;
			// block within area?
			if (address < (uint32)this + areaHeaderSize
				|| address + sizeof(TFreeBlock) > (uint32)this + fSize) {
				FATAL(("Utterly mislocated block: %p, area: %p, "
					   "size: %lu\n", block, this, fSize));
				BA_PANIC("Bad area block.");
				return false;
			}
			// block too large for area?
			size_t blockSize = block->GetSize();
			if (blockSize < sizeof(TFreeBlock)
				|| address + blockSize > (uint32)this + fSize) {
				FATAL(("Mislocated block: %p, size: %lu, area: %p, "
					   "size: %lu\n", block, blockSize, this, fSize));
				BA_PANIC("Bad area block.");
				return false;
			}
			// alignment
			if (block_align_floor(address) != address
				|| block_align_floor(blockSize) != blockSize) {
				FATAL(("Block %ld not properly aligned: %p, size: %lu\n",
					   i, block, blockSize));
				BA_PANIC("Bad area block.");
				return false;
			}
			// previous block
			if (block->GetPreviousBlock() != prevBlock) {
				FATAL(("Previous block of block %ld was not the previous "
					   "block in list: %p vs %p\n", i,
					   block->GetPreviousBlock(), prevBlock));
				BA_PANIC("Bad area block list.");
				return false;
			}
			// additional checks for free block list
			if (block->IsFree()) {
				freeBlockCount++;
				TFreeBlock *freeBlock = block->ToFreeBlock();
				if (prevFree)
					freeBytes += freeBlock->GetSize();
				else
					freeBytes += freeBlock->GetUsableSize();
				// block == next free block of previous free block
				if (freeBlock != nextFree) {
					FATAL(("Free block %ld is not the next block in free "
						   "list: %p vs %p\n", i, freeBlock, nextFree));
					BA_PANIC("Bad area free list.");
					return false;
				}
				// previous free block
				if (freeBlock->GetPreviousFreeBlock() != prevFree) {
					FATAL(("Previous free block of block %ld was not the "
						   " previous block in free list: %p vs %p\n", i,
						   freeBlock->GetPreviousFreeBlock(), prevFree));
					BA_PANIC("Bad area free list.");
					return false;
				}
				prevFree = freeBlock;
				nextFree = freeBlock->GetNextFreeBlock();
			} else
				usedBlockCount++;
			prevBlock = block;
			block = block->GetNextBlock();
			blockListOK = true;
		}
		// final checks on block list
		if (blockListOK) {
			if (block) {
				FATAL(("More blocks in block list than expected\n"));
				BA_PANIC("Bad area block count.");
				return false;
			} else if (fLastBlock != prevBlock) {
				FATAL(("last block in block list was %p, but should be "
					   "%p\n", fLastBlock, prevBlock));
				BA_PANIC("Bad area last block.");
				return false;
			} else if (prevFree != fLastFree) {
				FATAL(("last block in free list was %p, but should be %p\n",
					   fLastFree, prevFree));
				BA_PANIC("Bad area last free block.");
				return false;
			}
			// block counts (a bit reduntant)
			if (freeBlockCount != fFreeBlockCount) {
				FATAL(("Free block count is %ld, but should be %ld\n",
					   fFreeBlockCount, freeBlockCount));
				BA_PANIC("Bad area free block count.");
				return false;
			}
			if (usedBlockCount != fUsedBlockCount) {
				FATAL(("Used block count is %ld, but should be %ld\n",
					   fUsedBlockCount, usedBlockCount));
				BA_PANIC("Bad area used block count.");
				return false;
			}
			// free bytes
			if (fFreeBytes != freeBytes) {
				FATAL(("Free bytes is %lu, but should be %lu\n",
					   fFreeBytes, freeBytes));
				BA_PANIC("Bad area free bytes.");
				return false;
			}
		}
	}
	return true;
}
Esempio n. 2
0
// ResizeBlock
Block *
BlockAllocator::Area::ResizeBlock(Block *block, size_t newUsableSize,
								  bool dontDefragment)
{
//PRINT(("Area::ResizeBlock(%p, %lu)\n", block, newUsableSize));
// newUsableSize must be >0 !
	if (newUsableSize == 0)
		return NULL;
	Block *resultBlock = NULL;
	if (block) {
		size_t size = block->GetSize();
		size_t newSize = max(newUsableSize + sizeof(BlockHeader),
							 kMinBlockSize);
		newSize = block_align_ceil(newSize);
		if (newSize == size) {
			// size doesn't change: nothing to do
			resultBlock = block;
		} else if (newSize < size) {
			// shrink the block
			size_t sizeDiff = size - newSize;
			Block *nextBlock = block->GetNextBlock();
			if (nextBlock && nextBlock->IsFree()) {
				// join the space with the adjoining free block
				TFreeBlock *freeBlock = nextBlock->ToFreeBlock();
				_MoveResizeFreeBlock(freeBlock, -sizeDiff,
									 freeBlock->GetSize() + sizeDiff);
				// resize the block and we're done
				block->SetSize(newSize, true);
				fFreeBytes += sizeDiff;
			} else if (sizeDiff >= sizeof(TFreeBlock)) {
				// the freed space is large enough for a free block
				TFreeBlock *newFree = _MakeFreeBlock(block, newSize, block,
					sizeDiff, nextBlock, NULL, NULL);
				_InsertFreeBlock(newFree);
				block->SetSize(newSize, true);
				if (fFreeBlockCount == 1)
					fFreeBytes += newFree->GetUsableSize();
				else
					fFreeBytes += newFree->GetSize();
				if (!dontDefragment && _DefragmentingRecommended())
					_Defragment();
			}	// else: insufficient space for a free block: no changes
			resultBlock = block;
		} else {
//PRINT(("  grow...\n"));
			// grow the block
			size_t sizeDiff = newSize - size;
			Block *nextBlock = block->GetNextBlock();
			if (nextBlock && nextBlock->IsFree()
				&& nextBlock->GetSize() >= sizeDiff) {
//PRINT(("  adjoining free block\n"));
				// there is a adjoining free block and it is large enough
				TFreeBlock *freeBlock = nextBlock->ToFreeBlock();
				size_t freeSize = freeBlock->GetSize();
				if (freeSize - sizeDiff >= sizeof(TFreeBlock)) {
					// the remaining space is still large enough for a free
					// block
					_MoveResizeFreeBlock(freeBlock, sizeDiff,
										 freeSize - sizeDiff);
					block->SetSize(newSize, true);
					fFreeBytes -= sizeDiff;
				} else {
					// the remaining free space wouldn't be large enough for
					// a free block: consume the free block completely
					Block *freeNext = freeBlock->GetNextBlock();
					_RemoveFreeBlock(freeBlock);
					block->SetSize(size + freeSize, freeNext);
					_FixBlockList(block, block->GetPreviousBlock(), freeNext);
					if (fFreeBlockCount == 0)
						fFreeBytes = 0;
					else
						fFreeBytes -= freeSize;
				}
				resultBlock = block;
			} else {
//PRINT(("  no adjoining free block\n"));
				// no (large enough) adjoining free block: allocate
				// a new block and copy the data to it
				BlockReference *reference = block->GetReference();
				resultBlock = AllocateBlock(newUsableSize, dontDefragment);
				block = reference->GetBlock();
				if (resultBlock) {
					resultBlock->SetReference(reference);
					memcpy(resultBlock->GetData(), block->GetData(),
						   block->GetUsableSize());
					FreeBlock(block, dontDefragment);
					resultBlock = reference->GetBlock();
				}
			}
		}
	}
	D(SanityCheck());
//PRINT(("Area::ResizeBlock() done: %p\n", resultBlock));
	return resultBlock;
}