/* Coalesce 'oldBlock' with any preceeding or following free blocks. */ static void coalesceFreeBlock(BlockInfo* oldBlock) { BlockInfo *blockCursor; BlockInfo *newBlock; BlockInfo *freeBlock; // size of old block size_t oldSize = SIZE(oldBlock->sizeAndTags); // running sum to be size of final coalesced block size_t newSize = oldSize; // Coalesce with any preceding free block blockCursor = oldBlock; while ((blockCursor->sizeAndTags & TAG_PRECEDING_USED)==0) { // While the block preceding this one in memory (not the // prev. block in the free list) is free: // Get the size of the previous block from its boundary tag. size_t size = SIZE(*((size_t*)UNSCALED_POINTER_SUB(blockCursor, WORD_SIZE))); // Use this size to find the block info for that block. freeBlock = (BlockInfo*)UNSCALED_POINTER_SUB(blockCursor, size); // Remove that block from free list. removeFreeBlock(freeBlock); // Count that block's size and update the current block pointer. newSize += size; blockCursor = freeBlock; } newBlock = blockCursor; // Coalesce with any following free block. // Start with the block following this one in memory blockCursor = (BlockInfo*)UNSCALED_POINTER_ADD(oldBlock, oldSize); while ((blockCursor->sizeAndTags & TAG_USED)==0) { // While the block is free: size_t size = SIZE(blockCursor->sizeAndTags); // Remove it from the free list. removeFreeBlock(blockCursor); // Count its size and step to the following block. newSize += size; blockCursor = (BlockInfo*)UNSCALED_POINTER_ADD(blockCursor, size); } // If the block actually grew, remove the old entry from the free // list and add the new entry. if (newSize != oldSize) { // Remove the original block from the free list removeFreeBlock(oldBlock); // Save the new size in the block info and in the boundary tag // and tag it to show the preceding block is used (otherwise, it // would have become part of this one!). newBlock->sizeAndTags = newSize | TAG_PRECEDING_USED; // The boundary tag of the preceding block is the word immediately // preceding block in memory where we left off advancing blockCursor. *(size_t*)UNSCALED_POINTER_SUB(blockCursor, WORD_SIZE) = newSize | TAG_PRECEDING_USED; // Put the new block in the free list. insertFreeBlock(newBlock); } return; }
VboBlock* Vbo::freeBlock(VboBlock& block) { #ifdef _DEBUG_VBO checkBlockChain(); checkFreeBlocks(); #endif VboBlock* previous = block.m_previous; VboBlock* next = block.m_next; m_freeCapacity += block.capacity(); block.m_free = true; if (previous != NULL && previous->free() && next != NULL && next->free()) { resizeBlock(*previous, previous->capacity() + block.capacity() + next->capacity()); if (m_last == next) m_last = previous; removeFreeBlock(*next); previous->insertBetween(previous->m_previous, next->m_next); delete █ delete next; return previous; } if (previous != NULL && previous->free()) { resizeBlock(*previous, previous->capacity() + block.capacity()); if (m_last == &block) m_last = previous; previous->insertBetween(previous->m_previous, next); delete █ return previous; } if (next != NULL && next->free()) { if (m_last == next) m_last = █ removeFreeBlock(*next); block.m_capacity += next->capacity(); block.m_free = true; block.insertBetween(previous, next->m_next); insertFreeBlock(block); delete next; return █ } insertFreeBlock(block); #ifdef _DEBUG_VBO checkBlockChain(); checkFreeBlocks(); #endif return █ }
/* Allocate a block of size size and return a pointer to it. */ void * mm_malloc (size_t size) { size_t reqSize; BlockInfo * ptrFreeBlock = NULL; //Zero-size requests get NULL; if (size == 0){ return NULL; } //Add one word for the initial size header. //Note that we don't need to boundary tag when the block is used! if (size <= MIN_BLOCK_SIZE) { // Make sure we allocate enough space for a blockInfo in case we // free this block (when we free this block, we'll need to use the // next pointer, the prev pointer, and the boundary tag). reqSize = MIN_BLOCK_SIZE; } else { // Round up for correct alignment reqSize = ALIGNMENT * ((size + ALIGNMENT - 1) / ALIGNMENT); } printf("Begin malloc of reqSize: %zd \n", reqSize); printf("Free list head: %p\n", FREE_LIST_HEAD); examine_heap(); while ((ptrFreeBlock = searchFreeList(reqSize)) == NULL){ requestMoreSpace(reqSize); printf("Finished space request\n"); } removeFreeBlock(ptrFreeBlock); placeBlock(ptrFreeBlock, reqSize); printf("Completed malloc\n"); printf("Pointer free block: %p\n", ptrFreeBlock); examine_heap(); return UNSCALED_POINTER_ADD(ptrFreeBlock, WORD_SIZE); }
//set block allocates the chosen block by removing it from the free list/re-adding the remainder(from mem_sbrk) to the freelist static void setBlock(BlockInfo * block, size_t reqSize, size_t precedingBlockUseTag ){ BlockInfo * remainder; size_t size_allocated; size_allocated = (size_t)SIZE(block->sizeAndTags); //get the size of the block removeFreeBlock(block); //if we're allocating, we should remove from the free list if( (size_allocated - reqSize) > MIN_BLOCK_SIZE){ //calls to mem_sbrk allocate more memory than we need, let's put back what's left over after filling the request. block->sizeAndTags = reqSize | precedingBlockUseTag; //turn on the TAG_PRECEDING_USED for the else clause of mm_malloc remainder = (BlockInfo *)UNSCALED_POINTER_ADD(block, reqSize);//reqSize is the payload of the block we're trying to allocate, we move past that portion to access the remainder remainder->sizeAndTags = ((size_allocated - reqSize) | TAG_PRECEDING_USED);//the remainder is the block in the list immediately following the allocated. need to //turn on the preceding block used flag *((size_t *)UNSCALED_POINTER_ADD(block, (reqSize - WORD_SIZE))) = reqSize;//boundary tag for allocated block *((size_t *)UNSCALED_POINTER_ADD(block, (size_allocated - WORD_SIZE))) = (size_allocated - reqSize); //size for the remainder is the size actually allocated - the desired size insertFreeBlock(remainder);//re-insert remainder into the freeList } else{ *((size_t* )UNSCALED_POINTER_ADD(block,(size_allocated - WORD_SIZE))) = size_allocated; remainder = (BlockInfo *)UNSCALED_POINTER_ADD(block, size_allocated); remainder->sizeAndTags = remainder->sizeAndTags | TAG_PRECEDING_USED; } block->sizeAndTags = block->sizeAndTags | TAG_USED; block->sizeAndTags = block->sizeAndTags | precedingBlockUseTag; }
void Vbo::resizeBlock(VboBlock& block, size_t newCapacity) { if (block.capacity() == newCapacity) return; if (block.free()) { removeFreeBlock(block); block.m_capacity = newCapacity; insertFreeBlock(block); } }
VboBlock* Vbo::packBlock(VboBlock& block) { VboBlock* first = block.m_next; if (first == NULL) return NULL; VboBlock* previous = NULL; VboBlock* last = first; size_t size = 0; size_t address = first->address(); do { last->m_address -= block.capacity(); size += last->capacity(); previous = last; last = last->m_next; } while (last != NULL && !last->free()); memmove(m_buffer + block.address(), m_buffer + address, size); if (last != NULL) { last->m_address -= block.capacity(); resizeBlock(*last, last->capacity() + block.capacity()); } else { VboBlock* newBlock = new VboBlock(*this, previous->address() + previous->capacity(), block.capacity()); insertFreeBlock(*newBlock); newBlock->insertBetween(previous, NULL); m_last = newBlock; } if (m_first == &block) m_first = block.m_next; removeFreeBlock(block); if (block.m_previous != NULL) block.m_previous->m_next = block.m_next; if (block.m_next != NULL) block.m_next->m_previous = block.m_previous; delete █ return last; }
/* places block for malloc function into free block basically changing last byte to 1 in header, so that block is marked as not empty, if free Block is > tha what we need to allocate, also split free bloc, etc. */ static void * placeBlock(BlockInfo * freeBlock, size_t reqSize, size_t precedingBlockUseTag) { size_t sizeFree; BlockInfo * restOfFreeBlock; sizeFree = (size_t)SIZE( freeBlock->sizeAndTags ); //gives size without last 3 indicator bits removeFreeBlock(freeBlock); if( (sizeFree - reqSize) > MIN_BLOCK_SIZE ) { freeBlock->sizeAndTags = reqSize | precedingBlockUseTag; //printf("Ex-Free block after allocation 0x%x %d 0x%x 0x%x\n", // (int*)freeBlock, (int)freeBlock->sizeAndTags, (int*)freeBlock->next, (int*)freeBlock->prev); restOfFreeBlock = POINTER_ADD( freeBlock, reqSize ); restOfFreeBlock->sizeAndTags = ((sizeFree-reqSize) | TAG_PRECEDING_USED) & (~TAG_USED); //Updates the boundary tag *((int*)POINTER_ADD(freeBlock, (reqSize-WORD_SIZE))) = reqSize; *((int*)POINTER_ADD(freeBlock, (sizeFree-WORD_SIZE))) = sizeFree-reqSize; insertFreeBlock(restOfFreeBlock); //printf("Rest of free block after allocation 0x%x %d 0x%x 0x%x\n", // (int*)restOfFreeBlock, (int)restOfFreeBlock->sizeAndTags, (int*)restOfFreeBlock->next, (int*)restOfFreeBlock->prev); } else { //freeBlock->sizeAndTags = sizeFree | TAG_USED; // Updates the following blocks preceding used and the boundary tag *((int*)POINTER_ADD(freeBlock, (sizeFree-WORD_SIZE))) = sizeFree; restOfFreeBlock = (BlockInfo*)POINTER_ADD(freeBlock, sizeFree); restOfFreeBlock->sizeAndTags = restOfFreeBlock->sizeAndTags | TAG_PRECEDING_USED; } freeBlock->sizeAndTags |= TAG_USED; freeBlock->sizeAndTags |= precedingBlockUseTag; }
/* Allocate a block of size size and return a pointer to it. */ void* mm_malloc (size_t size) { size_t reqSize; BlockInfo * ptrFreeBlock = NULL; size_t blockSize; size_t precedingBlockUseTag; // Zero-size requests get NULL. if (size == 0) { return NULL; } // Add one word for the initial size header. // Note that we don't need to boundary tag when the block is used! size += WORD_SIZE; if (size <= MIN_BLOCK_SIZE) { // Make sure we allocate enough space for a blockInfo in case we // free this block (when we free this block, we'll need to use the // next pointer, the prev pointer, and the boundary tag). reqSize = MIN_BLOCK_SIZE; } else { // Round up for correct alignment reqSize = ALIGNMENT * ((size + ALIGNMENT - 1) / ALIGNMENT); } // Implement mm_malloc. You can change or remove any of the above // code. It is included as a suggestion of where to start. // You will want to replace this return statement... // Search the free list for a fit ptrFreeBlock = searchFreeList(reqSize); // No fit found. Get more memory if (ptrFreeBlock == NULL) { requestMoreSpace(reqSize); ptrFreeBlock = searchFreeList(reqSize); } // place the acquired block and split excessive part as needed removeFreeBlock(ptrFreeBlock); blockSize = SIZE(ptrFreeBlock->sizeAndTags); precedingBlockUseTag = ptrFreeBlock->sizeAndTags & TAG_PRECEDING_USED; if (blockSize - reqSize >= MIN_BLOCK_SIZE) { size_t newFreeBlockSize = blockSize - reqSize; BlockInfo *newPtrFreeBlock = (BlockInfo*)POINTER_ADD(ptrFreeBlock, reqSize); newPtrFreeBlock->sizeAndTags = newFreeBlockSize | TAG_PRECEDING_USED; // !TAG_USED // update the boundary tag *((size_t*)POINTER_ADD(newPtrFreeBlock, newFreeBlockSize - WORD_SIZE)) = newFreeBlockSize | TAG_PRECEDING_USED; // !TAG_USED // insert the new free block into free list insertFreeBlock(newPtrFreeBlock); blockSize = reqSize; } else { // do not need to split the block, but need to update the status of following block BlockInfo *followingBlock = (BlockInfo*)POINTER_ADD(ptrFreeBlock, blockSize); size_t followingBlockSize = SIZE(followingBlock->sizeAndTags); size_t followingBlockUsed = followingBlock->sizeAndTags & TAG_USED; followingBlock->sizeAndTags = followingBlockSize | TAG_PRECEDING_USED | followingBlockUsed; if (followingBlockUsed != TAG_USED) { *((size_t*)POINTER_ADD(followingBlock, followingBlockSize - WORD_SIZE)) = followingBlock->sizeAndTags; } } ptrFreeBlock->sizeAndTags = blockSize | precedingBlockUseTag | TAG_USED; // we do not care about the boundary tag of used block! return POINTER_ADD(ptrFreeBlock, WORD_SIZE); }
/* Allocate a block of size size and return a pointer to it. */ void* mm_malloc (size_t size) { size_t reqSize; BlockInfo * ptrFreeBlock = NULL; size_t blockSize; size_t precedingBlockUseTag; BlockInfo * nextBlock = NULL; BlockInfo * newBlock = NULL; // Zero-size requests get NULL. if (size == 0) { return NULL; } // Add one word for the initial size header. // Note that we don't need to boundary tag when the block is used! size += WORD_SIZE; if (size <= MIN_BLOCK_SIZE) { // Make sure we allocate enough space for a blockInfo in case we // free this block (when we free this block, we'll need to use the // next pointer, the prev pointer, and the boundary tag). reqSize = MIN_BLOCK_SIZE; } else { // Round up for correct alignment reqSize = ALIGNMENT * ((size + ALIGNMENT - 1) / ALIGNMENT); } // Implement mm_malloc. You can change or remove any of the above // code. It is included as a suggestion of where to start. // You will want to replace this return statement... /* ptrFreeBlock = searchFreeList(reqSize); if( ptrFreeBlock != NULL) { blockSize = SIZE(ptrFreeBlock->sizeAndTags); nextBlock = (BlockInfo* )POINTER_ADD(ptrFreeBlock, blockSize); nextBlock->sizeAndTags = nextBlock->sizeAndTags | TAG_PRECEDING_USED; removeFreeBlock(ptrFreeBlock); ptrFreeBlock->sizeAndTags = ptrFreeBlock->sizeAndTags | TAG_USED; return POINTER_ADD( ptrFreeBlock, WORD_SIZE); } requestMoreSpace(reqSize); ptrFreeBlock = searchFreeList(reqSize); if( ptrFreeBlock != NULL) { blockSize = SIZE(ptrFreeBlock->sizeAndTags); nextBlock = (BlockInfo* )POINTER_ADD(ptrFreeBlock, blockSize); nextBlock->sizeAndTags = nextBlock->sizeAndTags | TAG_PRECEDING_USED; removeFreeBlock(ptrFreeBlock); ptrFreeBlock->sizeAndTags = ptrFreeBlock->sizeAndTags | TAG_USED; return POINTER_ADD( ptrFreeBlock, WORD_SIZE); } */ ptrFreeBlock = searchFreeList(reqSize); if( ptrFreeBlock == NULL){ requestMoreSpace(reqSize); ptrFreeBlock = searchFreeList(reqSize); } blockSize = SIZE(ptrFreeBlock->sizeAndTags); if( (blockSize - reqSize) >= MIN_BLOCK_SIZE ){ precedingBlockUseTag = ptrFreeBlock->sizeAndTags & TAG_PRECEDING_USED; ptrFreeBlock->sizeAndTags = reqSize | precedingBlockUseTag | TAG_USED ; removeFreeBlock(ptrFreeBlock); newBlock = (BlockInfo* )POINTER_ADD(ptrFreeBlock, reqSize); newBlock->sizeAndTags = blockSize - reqSize; newBlock->sizeAndTags = newBlock->sizeAndTags | TAG_PRECEDING_USED; *((size_t*)POINTER_ADD(newBlock, blockSize - reqSize - WORD_SIZE ) ) = newBlock->sizeAndTags; insertFreeBlock(newBlock); }else{ nextBlock = (BlockInfo* )POINTER_ADD(ptrFreeBlock, blockSize); nextBlock->sizeAndTags = nextBlock->sizeAndTags | TAG_PRECEDING_USED; ptrFreeBlock->sizeAndTags = ptrFreeBlock->sizeAndTags | TAG_USED; removeFreeBlock(ptrFreeBlock); } return POINTER_ADD( ptrFreeBlock, WORD_SIZE); }
/* Allocate a block of size size and return a pointer to it. */ void* mm_malloc (size_t size) { size_t reqSize; BlockInfo * ptrFreeBlock = NULL; BlockInfo * splitBlock; size_t blockSize; size_t precedingBlockUseTag; // Zero-size requests get NULL. if (size == 0) { return NULL; } // Add one word for the initial size header. // Note that we don't need to boundary tag when the block is used! size += WORD_SIZE; if (size <= MIN_BLOCK_SIZE) { // Make sure we allocate enough space for a blockInfo in case we // free this block (when we free this block, we'll need to use the // next pointer, the prev pointer, and the boundary tag). reqSize = MIN_BLOCK_SIZE; } else { // Round up for correct alignment reqSize = ALIGNMENT * ((size + ALIGNMENT - 1) / ALIGNMENT); } // Implement mm_malloc. You can change or remove any of the above // code. It is included as a suggestion of where to start. // You will want to replace this return statement... // find free block of reqSize ptrFreeBlock = searchFreeList(reqSize); while ( ptrFreeBlock == NULL ) { requestMoreSpace(1 << 14); ptrFreeBlock = searchFreeList(reqSize); } // check free block size vs reqSize vs alignment requirements, // split if necessary. If split, reformat newly created free // block (add header, set bits, add footer). blockSize = SIZE(ptrFreeBlock->sizeAndTags); if ( blockSize - reqSize >= MIN_BLOCK_SIZE ) { // Split, set size and tags of new block splitBlock = (BlockInfo*) POINTER_ADD(ptrFreeBlock, reqSize); blockSize -= reqSize; splitBlock->sizeAndTags = blockSize | TAG_PRECEDING_USED; splitBlock->sizeAndTags &= ~0 << 1; // turn off use bit - preserve others // set footer equal to header. Current ptr + blockSize - one word = boundary // tag of current block (word prior to start of next block) *((size_t*) POINTER_ADD(splitBlock, blockSize- WORD_SIZE))= splitBlock->sizeAndTags; insertFreeBlock(splitBlock); // set size of ptrFreeBlock to exclude size of newBlock blockSize = reqSize; } else { // if we didnt split, set the next block's preceding tag to 1 *((size_t*) POINTER_ADD(ptrFreeBlock, SIZE(ptrFreeBlock->sizeAndTags))) |= TAG_PRECEDING_USED; } removeFreeBlock(ptrFreeBlock); precedingBlockUseTag = ptrFreeBlock->sizeAndTags & TAG_PRECEDING_USED; // if the preceding block is used as well, set lower two bits. Else, set only // used bit. if ( precedingBlockUseTag ) { ptrFreeBlock->sizeAndTags = blockSize | (TAG_PRECEDING_USED + TAG_USED); } else { ptrFreeBlock->sizeAndTags = blockSize | TAG_USED; } // return pointer to block (beginning of payload) // if null, return null. else return 8 after start of block (ie skip header, // return ptr to payload region) if ( ptrFreeBlock == NULL) { return NULL; } else { return (void*) POINTER_ADD(ptrFreeBlock, WORD_SIZE); } }