예제 #1
0
파일: heap.cpp 프로젝트: itavero/openthread
void *Heap::CAlloc(size_t aCount, size_t aSize)
{
    void *   ret  = NULL;
    Block *  prev = NULL;
    Block *  curr = NULL;
    uint16_t size = static_cast<uint16_t>(aCount * aSize);

    VerifyOrExit(size);

    size += kAlignSize - 1 - kBlockRemainderSize;
    size &= ~(kAlignSize - 1);
    size += kBlockRemainderSize;

    prev = &BlockSuper();
    curr = &BlockNext(*prev);

    while (curr->GetSize() < size)
    {
        prev = curr;
        curr = &BlockNext(*curr);
    }

    VerifyOrExit(curr->IsFree());

    prev->SetNext(curr->GetNext());

    if (curr->GetSize() > size + sizeof(Block))
    {
        const uint16_t newBlockSize = curr->GetSize() - size - sizeof(Block);
        curr->SetSize(size);

        Block &newBlock = BlockRight(*curr);
        newBlock.SetSize(newBlockSize);
        newBlock.SetNext(0);

        if (prev->GetSize() < newBlockSize)
        {
            BlockInsert(*prev, newBlock);
        }
        else
        {
            BlockInsert(BlockSuper(), newBlock);
        }
    }

    curr->SetNext(0);

    memset(curr->GetPointer(), 0, size);
    ret = curr->GetPointer();

exit:
    return ret;
}
예제 #2
0
파일: heap.cpp 프로젝트: itavero/openthread
void Heap::BlockInsert(Block &aPrev, Block &aBlock)
{
    Block *prev = &aPrev;

    for (Block *block = &BlockNext(*prev); block->GetSize() < aBlock.GetSize(); block = &BlockNext(*block))
    {
        prev = block;
    }

    aBlock.SetNext(prev->GetNext());
    prev->SetNext(BlockOffset(aBlock));
}
예제 #3
0
파일: block.cpp 프로젝트: japgo/mygithub
Block::Block(const Block& block)
{
	// Declare necessary variables
	Unit*	pUnit;
	Unit*	pNewUnit;

	// Initialize pimpl object
	_pPimpl = new BlockPimpl;
	assert(_pPimpl);

	// Get Block Data
	this->SetPosition	(block.GetPosition		());
	this->SetSize		(block.GetSize			());
	this->SetStartPoint	(block.GetStartPoint	());

	// Get Unit Data
	pUnit = block.FirstUnit();

	if (pUnit == NULL)
	{
		return;
	}

	do
	{
		pNewUnit = new Unit(*pUnit);

		if (pNewUnit == NULL)
		{
			continue;
		}

		this->InsertUnit(pNewUnit);
	}
	while ((pUnit = block.NextUnit()) != NULL);
}
예제 #4
0
// AllocateBlock
Block *
BlockAllocator::Area::AllocateBlock(size_t usableSize, bool dontDefragment)
{
if (kMinBlockSize != block_align_ceil(sizeof(TFreeBlock))) {
FATAL(("kMinBlockSize is not correctly initialized! Is %lu, but should be: "
"%lu\n", kMinBlockSize, block_align_ceil(sizeof(TFreeBlock))));
BA_PANIC("kMinBlockSize not correctly initialized.");
return NULL;
}
	if (usableSize == 0)
		return NULL;
	Block *newBlock = NULL;
	size_t size = max(usableSize + sizeof(BlockHeader), kMinBlockSize);
	size = block_align_ceil(size);
	if (size <= _GetBlockFreeBytes()) {
		// find first fit
		TFreeBlock *block = _FindFreeBlock(size);
		if (!block && !dontDefragment) {
			// defragmenting is necessary
			_Defragment();
			block = _FindFreeBlock(size);
			if (!block) {
				// no free block
				// Our data structures seem to be corrupted, since
				// _GetBlockFreeBytes() promised that we would have enough
				// free space.
				FATAL(("Couldn't find free block of min size %lu after "
					   "defragmenting, although we should have %lu usable free "
					   "bytes!\n", size, _GetBlockFreeBytes()));
				BA_PANIC("Bad area free bytes.");
			}
		}
		if (block) {
			// found a free block
			size_t remainder = block->GetSize() - size;
			if (remainder >= kMinBlockSize) {
				// enough space left for a free block
				Block *freePrev = block->GetPreviousBlock();
//				TFreeBlock *prevFree = block->GetPreviousFreeBlock();
//				TFreeBlock *nextFree = block->GetNextFreeBlock();
//				newBlock = block;
				_MoveResizeFreeBlock(block, size, remainder);
				// setup the new block
//				newBlock->SetSize(size, true);
//				newBlock->SetFree(false);
				newBlock = _MakeUsedBlock(block, 0, freePrev, size, true);
			} else {
				// not enough space left: take the free block over completely
				// remove the block from the free list
				_RemoveFreeBlock(block);
				newBlock = block;
				newBlock->SetFree(false);
			}
			if (fFreeBlockCount)
				fFreeBytes -= newBlock->GetSize();
			else
				fFreeBytes = 0;
			fUsedBlockCount++;
		}
	}
	D(SanityCheck());
	return newBlock;
}
예제 #5
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;
}
예제 #6
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;
}
예제 #7
0
파일: heap.cpp 프로젝트: itavero/openthread
void Heap::Free(void *aPointer)
{
    if (aPointer == NULL)
    {
        return;
    }

    Block &block = BlockOf(aPointer);
    Block &right = BlockRight(block);

    if (IsLeftFree(block))
    {
        Block *prev = &BlockSuper();
        Block *left = &BlockNext(*prev);

        for (const uint16_t offset = block.GetLeftNext(); left->GetNext() != offset; left = &BlockNext(*left))
        {
            prev = left;
        }

        // Remove left from free list.
        prev->SetNext(left->GetNext());
        left->SetNext(0);

        if (right.IsFree())
        {
            if (right.GetSize() > left->GetSize())
            {
                for (const uint16_t offset = BlockOffset(right); prev->GetNext() != offset; prev = &BlockNext(*prev))
                    ;
            }
            else
            {
                prev = &BlockPrev(right);
            }

            // Remove right from free list.
            prev->SetNext(right.GetNext());
            right.SetNext(0);

            // Add size of right.
            left->SetSize(left->GetSize() + right.GetSize() + sizeof(Block));
        }

        // Add size of current block.
        left->SetSize(left->GetSize() + block.GetSize() + sizeof(Block));

        BlockInsert(*prev, *left);
    }
    else
    {
        if (right.IsFree())
        {
            Block &prev = BlockPrev(right);
            prev.SetNext(right.GetNext());
            block.SetSize(block.GetSize() + right.GetSize() + sizeof(Block));
            BlockInsert(prev, block);
        }
        else
        {
            BlockInsert(BlockSuper(), block);
        }
    }
}