/*convenient function that find the correct free list and insert that free block*/ void insertToFreeList(void* bp) { size_t size = GET_SIZE(HDRP(bp)); int which = getWhichFreeList(size); //get the fit free list void* freeListHead = free_lists[which]; void* next = getNextFreeBlock(freeListHead); if (next == NULL) { //if the list is empty just insert to head insertFreeBlock(bp, freeListHead, NULL); return; } else { //find the correct position to insert using ordered address policy void* last = NULL; while (next != NULL) { if (bp > next) { void* prev = getPrevFreeBlock(next); insertFreeBlock(bp, prev, next); return; } void* nextnext = getNextFreeBlock(next); if (nextnext == NULL) { last = next; break; } next = nextnext; } //insert at the end of the free list insertFreeBlock(bp, last, NULL); 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 █ }
/* Free the block referenced by ptr. */ void mm_free (void *ptr) { size_t payloadSize; BlockInfo * blockInfo; BlockInfo * followingBlock; size_t bitMask; // Implement mm_free. You can change or remove the declaraions // above. They are included as minor hints. // set BlockInfo pointer to include header blockInfo = (BlockInfo*) POINTER_SUB(ptr, WORD_SIZE); payloadSize = SIZE(blockInfo->sizeAndTags) - WORD_SIZE; followingBlock = (BlockInfo*) POINTER_ADD(ptr, payloadSize + WORD_SIZE); // set header (first tags, then size) bitMask = ~0 << 1; blockInfo->sizeAndTags &= bitMask; /* preserves all bits, except sets lowest to 0 (unsetting used tag) */ // copy header into footer *((size_t*) POINTER_ADD(blockInfo, payloadSize)) = blockInfo->sizeAndTags; // set preceding use tag for following block bitMask = (~0 << 2) | 1; followingBlock->sizeAndTags &= bitMask; /* preserves all bits except 2nd lowest bit */ // insert into free list and coalesce insertFreeBlock(blockInfo); coalesceFreeBlock(blockInfo); }
//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; }
/* Free the block referenced by ptr. */ void mm_free (void *ptr) { size_t payloadSize; BlockInfo * blockInfo; BlockInfo * followingBlock; // Implement mm_free. You can change or remove the declaraions // above. They are included as minor hints. // Casts void pointer into BlockInfo, subtracts pointer by Wsize blockInfo = (BlockInfo*)POINTER_SUB(ptr, WORD_SIZE); // Checks if block wasn't freed if(((blockInfo->sizeAndTags) & TAG_USED)==0){ return; } // Marks it as free, adds to free list and coalesces the free blocks together. blockInfo->sizeAndTags = blockInfo->sizeAndTags & (~TAG_USED); insertFreeBlock(blockInfo); coalesceFreeBlock(blockInfo); // unmarks the next block's preced used tag payloadSize = SIZE(blockInfo->sizeAndTags); followingBlock = (BlockInfo*)POINTER_ADD(blockInfo, payloadSize); followingBlock->sizeAndTags = followingBlock->sizeAndTags & (~TAG_PRECEDING_USED); }
/* 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; }
// Split a large block into two sub-blocks. // spaceLeft and size are in words void *splitFreeBlock(void* blockToSplit, uint64_t spaceLeft, uint32_t size, void* currentFreeBlock, struct freeBlockLinks *currentBlockLinks) { // Reinitialise header of first sub-block. void* block = ADDRESS_MINUS_OFFSET(blockToSplit, blockHeader); struct blockHeader *allocatedBlock = INIT_STRUCT(blockHeader, block); allocatedBlock->attribute = size; // Create and initialise new node. uint32_t sizeNewNode = spaceLeft - BYTES_TO_WORDS(sizeof(blockHeader)); uint64_t sizeOffset = WORDS_TO_BYTES(size); void* endUserRequestedBlock = blockToSplit + sizeOffset; // initialise new block. void* prevBlock = PREV_BLOCK(currentBlockLinks); totalFreeSpace -= WORDS_TO_BYTES(spaceLeft); totalFreeSpace -= WORDS_TO_BYTES(size); // Stats initialiseFreeBlock(endUserRequestedBlock, sizeNewNode, prevBlock, currentFreeBlock, false, true); insertFreeBlock(endUserRequestedBlock, currentBlockLinks); return endUserRequestedBlock; }
/* Get more heap space of size at least reqSize. */ static void requestMoreSpace(size_t reqSize) { size_t pagesize = mem_pagesize(); size_t numPages = (reqSize + pagesize - 1) / pagesize; BlockInfo *newBlock; size_t totalSize = numPages * pagesize; size_t prevLastWordMask; void* mem_sbrk_result = mem_sbrk(totalSize); if ((size_t)mem_sbrk_result == -1) { printf("ERROR: mem_sbrk failed in requestMoreSpace\n"); exit(0); } newBlock = (BlockInfo*)UNSCALED_POINTER_SUB(mem_sbrk_result, WORD_SIZE); /* initialize header, inherit TAG_PRECEDING_USED status from the previously useless last word however, reset the fake TAG_USED bit */ printf("newBlock: %p\n", (void *) newBlock); prevLastWordMask = newBlock->sizeAndTags & TAG_PRECEDING_USED; newBlock->sizeAndTags = totalSize | prevLastWordMask; // Initialize boundary tag. ((BlockInfo*)UNSCALED_POINTER_ADD(newBlock, totalSize - WORD_SIZE))->sizeAndTags = totalSize | prevLastWordMask; /* initialize "new" useless last word the previous block is free at this moment but this word is useless, so its use bit is set This trick lets us do the "normal" check even at the end of the heap and avoid a special check to see if the following block is the end of the heap... */ *((size_t*)UNSCALED_POINTER_ADD(newBlock, totalSize)) = TAG_USED; // Add the new block to the free list and immediately coalesce newly // allocated memory space insertFreeBlock(newBlock); coalesceFreeBlock(newBlock); }
/* Free the block referenced by ptr. */ void mm_free (void *ptr) { size_t payloadSize; BlockInfo * blockInfo; BlockInfo * followingBlock; // Implement mm_free. You can change or remove the declaraions // above. They are included as minor hints. blockInfo = (BlockInfo*)POINTER_SUB(ptr, WORD_SIZE); payloadSize = SIZE(blockInfo->sizeAndTags); followingBlock = (BlockInfo*)POINTER_ADD(blockInfo, payloadSize); // update the status in the current block: reset TAG_USED in both head and boundary tag size_t precedingBlockUseTag = blockInfo->sizeAndTags & TAG_PRECEDING_USED; blockInfo->sizeAndTags = payloadSize | precedingBlockUseTag; *((size_t*)POINTER_ADD(blockInfo, payloadSize - WORD_SIZE)) = payloadSize | precedingBlockUseTag; // update the status in the following block: reset TAG_PRECEDING_USED size_t followingBlockSize = SIZE(followingBlock->sizeAndTags); size_t followingBlockUsed = followingBlock->sizeAndTags & TAG_USED; followingBlock->sizeAndTags = followingBlockSize | followingBlockUsed; // if the following block is free, also update its boundary tag if ((followingBlock->sizeAndTags & TAG_USED) != TAG_USED) { *((size_t*)POINTER_ADD(followingBlock, followingBlockSize - WORD_SIZE)) = followingBlock->sizeAndTags; } insertFreeBlock(blockInfo); coalesceFreeBlock(blockInfo); }
void Vbo::resizeBlock(VboBlock& block, size_t newCapacity) { if (block.capacity() == newCapacity) return; if (block.free()) { removeFreeBlock(block); block.m_capacity = newCapacity; insertFreeBlock(block); } }
Block & createBlock(char * ptr, size_t size, bool free) { assert(blocks.count(ptr) == 0); blocks[ptr] = Block(ptr, size, free); if(free) insertFreeBlock(blocks[ptr]); return blocks[ptr]; }
void resizeBlock(Block & block, size_t newSize) { if(newSize != block.size) { if(block.free) eraseFreeBlock(block); block.size = newSize; if(block.free) insertFreeBlock(block); } }
VboBlock* Vbo::allocBlock(size_t capacity) { assert(capacity > 0); #ifdef _DEBUG_VBO checkBlockChain(); checkFreeBlocks(); #endif size_t index = findFreeBlock(0, capacity); if (index >= m_freeBlocks.size()) { SetVboState mapVbo(*this, VboMapped); pack(); if (capacity > m_freeCapacity) { const size_t usedCapacity = m_totalCapacity - m_freeCapacity; size_t newCapacity = m_totalCapacity; size_t newFreeCapacity = m_freeCapacity; while (capacity > newFreeCapacity) { newCapacity *= 2; newFreeCapacity = newCapacity - usedCapacity; } resizeVbo(newCapacity); } index = findFreeBlock(0, capacity); assert(index < m_freeBlocks.size()); } VboBlock* block = m_freeBlocks[index]; std::vector<VboBlock*>::iterator it = m_freeBlocks.begin(); std::advance(it, index); m_freeBlocks.erase(it); // split block if (capacity < block->capacity()) { VboBlock* remainder = new VboBlock(*this, block->address() + capacity, block->capacity() - capacity); remainder->insertBetween(block, block->m_next); block->m_capacity = capacity; insertFreeBlock(*remainder); if (m_last == block) m_last = remainder; } m_freeCapacity -= block->capacity(); block->m_free = false; #ifdef _DEBUG_VBO checkBlockChain(); checkFreeBlocks(); #endif return block; }
/* Free the block referenced by ptr. */ void mm_free (void *ptr) { size_t payloadSize; BlockInfo * blockInfo; BlockInfo * followingBlock; blockInfo = (BlockInfo *)UNSCALED_POINTER_SUB(ptr, WORD_SIZE);//header of chosen block to free blockInfo->sizeAndTags = blockInfo->sizeAndTags & (~TAG_USED);//turn off the tag used tag payloadSize = SIZE(blockInfo->sizeAndTags);//get the payload of the block soon to be freed followingBlock = (BlockInfo *)UNSCALED_POINTER_ADD(blockInfo, payloadSize + WORD_SIZE);//move to the block that follows the block to be freed followingBlock->sizeAndTags = (followingBlock->sizeAndTags) & (~TAG_PRECEDING_USED);//turn off its preceding tag used flag insertFreeBlock(blockInfo);//insert block that was freed back to the list coalesceFreeBlock(blockInfo);//coalesce, if possible }
/* Free the block referenced by ptr. */ void mm_free (void *ptr) { size_t payloadSize; BlockInfo * blockInfo; BlockInfo * nextBlock; // Implement mm_free. You can change or remove the declaraions // above. They are included as minor hints. blockInfo = (BlockInfo* )POINTER_SUB(ptr, WORD_SIZE); payloadSize = SIZE(blockInfo->sizeAndTags); blockInfo->sizeAndTags = blockInfo->sizeAndTags & ~TAG_USED; *((size_t*)POINTER_ADD(blockInfo, payloadSize- WORD_SIZE)) = blockInfo->sizeAndTags; nextBlock = (BlockInfo* )POINTER_ADD(blockInfo, payloadSize); nextBlock->sizeAndTags = nextBlock->sizeAndTags & ~TAG_PRECEDING_USED; insertFreeBlock(blockInfo); coalesceFreeBlock(blockInfo); }
/* Free the block referenced by ptr. */ void mm_free (void *ptr) { printf("Begin free\n"); size_t payloadSize; BlockInfo * blockInfo; BlockInfo * footer; BlockInfo * nextBlock; size_t precedingBlockUseTag; blockInfo = (BlockInfo *) UNSCALED_POINTER_SUB(ptr, WORD_SIZE); payloadSize = SIZE(blockInfo->sizeAndTags); precedingBlockUseTag = blockInfo->sizeAndTags & TAG_PRECEDING_USED; blockInfo->sizeAndTags = (payloadSize & ~TAG_USED) | precedingBlockUseTag; footer = (BlockInfo *) UNSCALED_POINTER_ADD(blockInfo, payloadSize - WORD_SIZE); footer->sizeAndTags = blockInfo->sizeAndTags; nextBlock = (BlockInfo *) UNSCALED_POINTER_ADD(ptr, payloadSize); set_next_block(nextBlock, precedingBlockUseTag); insertFreeBlock(blockInfo); coalesceFreeBlock(blockInfo); }
void split_block(BlockInfo * ptrFreeBlock, size_t totalSize, size_t precedingBlockUseTag){ printf("Splitting\n"); BlockInfo * splitBlock = NULL; BlockInfo * splitBlockFooter = NULL; BlockInfo * nextBlock = NULL; size_t splitBlockSize; size_t ptrFreeBlockSize; ptrFreeBlockSize = SIZE(ptrFreeBlock->sizeAndTags); splitBlock = (BlockInfo *) UNSCALED_POINTER_ADD(ptrFreeBlock, ptrFreeBlockSize); splitBlockSize = totalSize - ptrFreeBlockSize; splitBlock->sizeAndTags = splitBlockSize | TAG_PRECEDING_USED; splitBlockFooter = (BlockInfo *) UNSCALED_POINTER_ADD((void*)splitBlock, splitBlockSize - WORD_SIZE); splitBlockFooter->sizeAndTags = splitBlock->sizeAndTags; nextBlock = (BlockInfo *) UNSCALED_POINTER_ADD((void *) splitBlock, splitBlockSize); set_next_block(nextBlock, 0); insertFreeBlock(splitBlock); coalesceFreeBlock(splitBlock); examine_heap(); }
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; }
void ThreadCache::freeObject(void* ptr) { // Here you will return the object to the free list sorted by address // and you will coalesce it if possible. ObjHeader* obj = reinterpret_cast<ObjHeader*>((unsigned char*)ptr - sizeof(ObjHeader)); size_t totalSize = obj->_objectSize; _m.lock(); // No space to put it into free-list (min: 48 bytes) if (totalSize < (sizeof(DualLnkNode) + 2 * sizeof(ObjHeader))) { _m.unlock(); puts("Free without gettting back-------------"); return; } else { obj->_flags = ObjFree; // "obj" now points to the Footer, set footer values obj = (ObjHeader*)((unsigned char*)obj+totalSize - sizeof(ObjHeader)); obj->_flags = ObjFree; // Set footer flag to freed // "obj" still points to the footer now assert(insertFreeBlock((DualLnkNode*)ptr, (totalSize / 8))); _m.unlock(); } }
// size free region in bytes void initialiseFreeMmapRegion(void* beginningFreeRegion, uint64_t sizeFreeRegion) { uint32_t sizeFreeRegionInWords = BYTES_TO_WORDS(sizeFreeRegion); // headerMmapsize in words. if(!freeList) { freeList = beginningFreeRegion; // Initialise the free list. initialiseFreeBlock(beginningFreeRegion, sizeFreeRegionInWords, beginningFreeRegion, beginningFreeRegion, false, true); } else { // Add to free list. void *currentBlock = freeList; void* links = ADDRESS_PLUS_OFFSET(currentBlock, blockHeader); struct freeBlockLinks *currentBlockLinks = INIT_STRUCT(freeBlockLinks, links); void* prevBlock = PREV_BLOCK(currentBlockLinks); initialiseFreeBlock(beginningFreeRegion, sizeFreeRegionInWords, prevBlock, currentBlock, false, true); // Tell next block that its previous one is NOW free. uint64_t sizeOffset = WORDS_TO_BYTES(sizeFreeRegionInWords); updateNextBlockOnCoalescing(beginningFreeRegion, sizeFreeRegion); insertFreeBlock(beginningFreeRegion, currentBlockLinks); } }
/* 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; 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; 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); }
void coalescingAndFree(void* block) { struct blockHeader *header = INIT_STRUCT(blockHeader, block); uint32_t size = GET_SIZE(header->attribute); // in words uint32_t flag = GET_FLAG(header->attribute); NEIGHBOUR_BLOCKS state = NEIGHBOUR_BLOCKS_NOT_FREE; struct freeBlockLinks *successorBlockLinks = NULL; // update only if necessary // Initialise addr and size for no change. void* newAddr = block; uint32_t newSize = size; uint64_t sizeOffset; // Is precedent block free? if (flag == MSB_TO_ONE) { state = NEIGHBOUR_BLOCKS_PRECEDENT_FREE; // In this case it's just about updating the size of the prev free block // and removing the successive one if free. void* footer = ADDRESS_MINUS_OFFSET(block, freeBlockFooter); struct freeBlockFooter *prevBlockFooter = INIT_STRUCT(freeBlockFooter, footer); sizeOffset = WORDS_TO_BYTES(prevBlockFooter->size); // Footer has no flag. newAddr = block - sizeOffset - sizeof(blockHeader); newSize = prevBlockFooter->size + BYTES_TO_WORDS(sizeof(blockHeader)) + size; } // Is successive block free? sizeOffset = WORDS_TO_BYTES(size); void* nextBlock = ADDRESS_PLUS_OFFSET(block + sizeOffset, blockHeader); struct blockHeader *nextHeader = INIT_STRUCT(blockHeader, nextBlock); if (nextHeader->attribute != MSB_TO_ZERO) { // check if next block is mmap footer or not. uint32_t nextSize = GET_SIZE(nextHeader->attribute); sizeOffset = WORDS_TO_BYTES(nextSize); void* nextNextBlock = ADDRESS_PLUS_OFFSET(nextBlock + sizeOffset, blockHeader); struct blockHeader *nextNextHeader = INIT_STRUCT(blockHeader, nextNextBlock); if (nextNextHeader->attribute != MSB_TO_ZERO) { flag = GET_FLAG(nextNextHeader->attribute); if (flag == MSB_TO_ONE) { if (!state) { state = NEIGHBOUR_BLOCKS_SUCCESSIVE_FREE; // Do not change address, but Increase size newSize = size + BYTES_TO_WORDS(sizeof(blockHeader)) + nextSize; } else { state = NEIGHBOUR_BLOCKS_BOTH_FREE; newSize = newSize + BYTES_TO_WORDS(sizeof(blockHeader)) + nextSize; } successorBlockLinks = nextBlock + sizeof(blockHeader); // IF NO PREV block is free: // Just update the pointers of the prev and next blocks // relative to this block AND the size. } } } // Otherwise it's next block is the mmap footer. switch(state) { case NEIGHBOUR_BLOCKS_NOT_FREE: { void *currentBlock = freeList; struct freeBlockLinks *currentBlockLinks = ADDRESS_PLUS_OFFSET(currentBlock, blockHeader); void* prevBlock = PREV_BLOCK(currentBlockLinks); initialiseFreeBlock(newAddr, newSize, prevBlock, currentBlock, false, false); // Tell next block that its previous one is NOW free. sizeOffset = WORDS_TO_BYTES(size); updateNextBlockOnCoalescing(newAddr, sizeOffset); insertFreeBlock(newAddr, currentBlockLinks); numberFreeBlocks++; break; } case NEIGHBOUR_BLOCKS_PRECEDENT_FREE: { coalesceWithPrevBlock(newAddr, newSize); break; } case NEIGHBOUR_BLOCKS_SUCCESSIVE_FREE: { coalesceWithNextBlock(newAddr, newSize, successorBlockLinks); break; } case NEIGHBOUR_BLOCKS_BOTH_FREE: { coalesceWithNeighbours(newAddr, newSize, successorBlockLinks); break; } default: { fprintf(stderr, "memoryManagement.coalescingAndFree - NEIGHBOUR_BLOCKS state unknown\n"); exit(-1); } } // end switch // Update total free space // When state == 0, the totalFreeSpace is updated when the block is initialised. totalFreeSpace += WORDS_TO_BYTES(size); // Stats if (state != NEIGHBOUR_BLOCKS_NOT_FREE) totalFreeSpace += sizeof(blockHeader); // Largest free region if (newSize > largestFreeBlock) largestFreeBlock = newSize; freeList = newAddr; }
void* ThreadCache::allocateObject(size_t size) { //Make sure that allocator is initialized if (!_initialized) { if (__sync_bool_compare_and_swap(&_initialized, 0, 1)) initialize(); } // Add the ObjHeader and Footer to the size and round the total size // up to a multiple of 8 bytes for alignment. size_t totalSize = (size + (sizeof(ObjHeader) << 1) + 7) & ~7; // Min = 48, has to have space to fill in "DualLnkNode" totalSize = (totalSize < 48)? 48 : totalSize; // You should get memory from the OS only if the memory in the free // list could not satisfy the request. void* mem; size_t index = (totalSize / 8 > NUMOFSIZECLASSES -1)? (NUMOFSIZECLASSES - 1) : (totalSize / 8); // Lock the shared doubly-linked-list-of-lists heap: _m.lock(); if (freels_[index++] != NULL) { // if 0 <= index <= 63, "mem" won't be NULL, since // freels_[index] != NULL mem = static_cast<void*>(rmFromFreeLs(totalSize / 8, totalSize)); if (mem != NULL) { // suitable size free node found mem = (void*)((unsigned char*)mem - sizeof(ObjHeader)); } else { // requesting > 512 bytes, not suitable free node exist mem = getMemoryFromCentHeap(totalSize); } // If the actual size for 'mem' is larger than totalSize, reassign if (((ObjHeader*)mem)->_objectSize > totalSize) { totalSize = ((ObjHeader*)mem)->_objectSize; } } else { // Search for larger free-lists in "freels_[]" while (index < NUMOFSIZECLASSES) { // search for larger slots if (freels_[index] != NULL) break; ++index; } if (index == NUMOFSIZECLASSES) { mem = getMemoryFromCentHeap(totalSize); // If the actual size for 'mem' is larger than totalSize, reassign if (((ObjHeader*)mem)->_objectSize > totalSize) { totalSize = ((ObjHeader*)mem)->_objectSize; } } else { // Split larger free slot DualLnkNode* toSplit = rmFromFreeLs(index, index * 8); size_t realSize = ((ObjHeader*)((unsigned char*)toSplit - sizeof(ObjHeader)))->_objectSize; if (realSize >= (totalSize + sizeof(DualLnkNode) + 2 * sizeof(ObjHeader))) { size_t newclass = (realSize - totalSize) / 8; // Set header and footer for new splitted object ObjHeader* splitobj = (ObjHeader*)((unsigned char*)toSplit + totalSize - sizeof(ObjHeader)); splitobj->_objectSize = realSize - totalSize; // may > sizeclass splitobj->_flags = ObjFree; splitobj = (ObjHeader*)((unsigned char*)toSplit + realSize - 2 * sizeof(ObjHeader)); // Now, pointing to footer splitobj->_objectSize = realSize - totalSize; // may > sizeclass splitobj->_flags = ObjFree; assert(insertFreeBlock((DualLnkNode*)((unsigned char*)toSplit + totalSize), newclass)); mem = (void*)((unsigned char*)toSplit - sizeof(ObjHeader)); } else { // Cannot split totalSize = realSize; // Gave a larger free-node back mem = (void*)((unsigned char*)toSplit - sizeof(ObjHeader)); } } } _m.unlock(); // Get a pointer to the object header ????? didn't change footer ObjHeader* obj = static_cast<ObjHeader*>(mem); // Store the totalSize. We will need it in realloc() and in free() obj->_objectSize = totalSize; // Set object as allocated obj->_flags = ObjAllocated; // "obj" now points to the Footer, set footer values obj = (ObjHeader*)((unsigned char*)obj + totalSize - sizeof(ObjHeader)); obj->_objectSize = totalSize; obj->_flags = ObjAllocated; // "obj" repoints to the header obj = (ObjHeader*)((unsigned char*)obj - totalSize + sizeof(ObjHeader)); // Return the pointer after the object header. return static_cast<void*>(obj + 1); }
void markBlockFree(Block & block) { assert(block.free == false); block.free = true; insertFreeBlock(block); }
/* 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); } }
void Vbo::resizeVbo(size_t newCapacity) { VboState oldState = m_state; unsigned char* temp = NULL; MemBlock::List memBlocks; if (m_vboId != 0 && m_freeCapacity < m_totalCapacity) { VboBlock* currentBlock = m_first; size_t totalLength = 0; while (currentBlock != NULL) { while (currentBlock != NULL && currentBlock->free()) currentBlock = currentBlock->m_next; if (currentBlock != NULL) { size_t start = currentBlock->address(); size_t length = 0; while (currentBlock != NULL && !currentBlock->free()) { length += currentBlock->capacity(); currentBlock = currentBlock->m_next; } memBlocks.push_back(MemBlock(start, length)); totalLength += length; } } if (m_state < VboActive) activate(); if (m_state < VboMapped) map(); temp = new unsigned char[totalLength]; size_t offset = 0; MemBlock::List::const_iterator it, end; for (it = memBlocks.begin(), end = memBlocks.end(); it != end; ++it) { const MemBlock& memBlock = *it; memcpy(temp + offset, m_buffer + memBlock.start, memBlock.length); offset += memBlock.length; } } size_t addedCapacity = newCapacity - m_totalCapacity; m_freeCapacity = newCapacity - (m_totalCapacity - m_freeCapacity); m_totalCapacity = newCapacity; if (m_last->free()) { resizeBlock(*m_last, m_last->capacity() + addedCapacity); } else { VboBlock* block = new VboBlock(*this, m_last->address() + m_last->capacity(), addedCapacity); block->insertBetween(m_last, NULL); insertFreeBlock(*block); m_last = block; } if (m_vboId != 0) { if (m_state == VboMapped) unmap(); if (m_state == VboActive) deactivate(); glDeleteBuffers(1, &m_vboId); m_vboId = 0; } if (temp != NULL) { assert(!memBlocks.empty()); if (m_state < VboActive) activate(); if (m_state < VboMapped) map(); size_t offset = 0; MemBlock::List::const_iterator it, end; for (it = memBlocks.begin(), end = memBlocks.end(); it != end; ++it) { const MemBlock& memBlock = *it; memcpy(m_buffer + memBlock.start, temp + offset, memBlock.length); } delete [] temp; temp = NULL; memBlocks.clear(); if (oldState < VboMapped) unmap(); if (oldState < VboActive) deactivate(); } else { if (oldState > VboInactive && m_state < VboActive) activate(); if (oldState > VboActive && m_state < VboMapped) map(); } #ifdef _DEBUG_VBO checkBlockChain(); checkFreeBlocks(); #endif }