Exemplo n.º 1
0
// CheckBlock
bool
BlockAllocator::Area::CheckBlock(Block *checkBlock, size_t minSize)
{
	for (Block *block = fFirstBlock; block; block = block->GetNextBlock()) {
		if (block == checkBlock)
			return (block->GetUsableSize() >= minSize);
	}
	FATAL(("Block %p is not in area %p!\n", checkBlock, this));
	BA_PANIC("Invalid Block.");
	return false;
}
Exemplo n.º 2
0
// _MakeUsedBlock
inline
Block *
BlockAllocator::Area::_MakeUsedBlock(void *address, ssize_t offset,
									 Block *previous, size_t size,
									 bool hasNext)
{
	Block *block = (Block*)((char*)address + offset);
	block->SetTo(previous, size, false, hasNext, NULL);
	if (hasNext)
		block->GetNextBlock()->SetPreviousBlock(block);
	else
		fLastBlock = block;
	return block;
}
Exemplo n.º 3
0
// _Defragment
void
BlockAllocator::Area::_Defragment()
{
D(SanityCheck());
//PRINT(("BlockAllocator::Area::_Defragment()\n"));
	// A trivial strategy for now: Keep the last free block and move the
	// others so that they can be joined with it. This is done iteratively
	// by moving the first free block to adjoin to the second one and
	// coalescing them. A free block is moved by moving the data blocks in
	// between.
	TFreeBlock *nextFree = NULL;
	while (fFirstFree && (nextFree = fFirstFree->GetNextFreeBlock()) != NULL) {
		Block *prevBlock = fFirstFree->GetPreviousBlock();
		Block *nextBlock = fFirstFree->GetNextBlock();
		size_t size = fFirstFree->GetSize();
		// Used blocks are relatively position independed. We can move them
		// en bloc and only need to adjust the previous pointer of the first
		// one.
		if (!nextBlock->IsFree()) {
			// move the used blocks
			size_t chunkSize = (char*)nextFree - (char*)nextBlock;
			Block *nextFreePrev = nextFree->GetPreviousBlock();
			Block *movedBlock = fFirstFree;
			memmove(movedBlock, nextBlock, chunkSize);
			movedBlock->SetPreviousBlock(prevBlock);
			// init the first free block
			Block *movedNextFreePrev = (Block*)((char*)nextFreePrev - size);
			fFirstFree = _MakeFreeBlock(movedBlock, chunkSize,
				movedNextFreePrev, size, true, NULL, nextFree);
			nextFree->SetPreviousFreeBlock(fFirstFree);
			// fix the references of the moved blocks
			for (Block *block = movedBlock;
				 block != fFirstFree;
				 block = block->GetNextBlock()) {
				block->FixReference();
			}
		} else {
			// uncoalesced adjoining free block: That should never happen,
			// since we always coalesce as early as possible.
			INFORM(("Warning: Found uncoalesced adjoining free blocks!\n"));
		}
		// coalesce the first two blocks
D(SanityCheck());
		_CoalesceWithNext(fFirstFree);
D(SanityCheck());
	}
//D(SanityCheck());
//PRINT(("BlockAllocator::Area::_Defragment() done\n"));
}
Exemplo n.º 4
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;
}