void coalesceWithNextBlock(void* newAddr, uint32_t newSize, struct freeBlockLinks *successorBlockLinks) { struct blockHeader *newBlock = newAddr; newBlock->attribute = newSize; // Update links to freenodes. void* blockLinks = ADDRESS_PLUS_OFFSET(newAddr, blockHeader); struct freeBlockLinks *newBlockLinks = INIT_STRUCT(freeBlockLinks, blockLinks); PREV_BLOCK(newBlockLinks) = PREV_BLOCK(successorBlockLinks); NEXT_BLOCK(newBlockLinks) = NEXT_BLOCK(successorBlockLinks); // Prev block. void* prevLinks = ADDRESS_PLUS_OFFSET(PREV_BLOCK(newBlockLinks), blockHeader); struct freeBlockLinks *prevBlockLinks = INIT_STRUCT(freeBlockLinks, prevLinks); NEXT_BLOCK(prevBlockLinks) = newAddr; // Next block. void* nextLinks = ADDRESS_PLUS_OFFSET(NEXT_BLOCK(newBlockLinks), blockHeader); struct freeBlockLinks *nextBlockLinks = INIT_STRUCT(freeBlockLinks, nextLinks); PREV_BLOCK(prevBlockLinks) = newAddr; uint64_t sizeOffset = WORDS_TO_BYTES(newSize); setFooterBlockOnCoalescing(newAddr, sizeOffset, newSize); updateNextBlockOnCoalescing(newAddr, sizeOffset); }
// Remove allocated block from free list. void removeAllocatedBlock(struct freeBlockLinks *blockToBeRemovedLinks) { void* prevBlock = PREV_BLOCK(blockToBeRemovedLinks); void* prevLinks = ADDRESS_PLUS_OFFSET(prevBlock, blockHeader); struct freeBlockLinks *prevBlockLinks = INIT_STRUCT(freeBlockLinks, prevLinks); NEXT_BLOCK(prevBlockLinks) = NEXT_BLOCK(blockToBeRemovedLinks); void* nextBlock = NEXT_BLOCK(blockToBeRemovedLinks); void* nextLinks = ADDRESS_PLUS_OFFSET(nextBlock, blockHeader); struct freeBlockLinks *nextBlockLinks = INIT_STRUCT(freeBlockLinks, nextLinks); PREV_BLOCK(nextBlockLinks) = PREV_BLOCK(blockToBeRemovedLinks); }
// Insert new free block into the free list void insertFreeBlock(void* newBlock, struct freeBlockLinks *prevBlockLinks) { void* usableArea = ADDRESS_PLUS_OFFSET(newBlock, blockHeader); struct freeBlockLinks *newBlockLinks = INIT_STRUCT(freeBlockLinks, usableArea); void* next = NEXT_BLOCK(newBlockLinks) + sizeof(blockHeader); struct freeBlockLinks *nextBlock = INIT_STRUCT(freeBlockLinks, next); PREV_BLOCK(nextBlock) = newBlock; void* prev = PREV_BLOCK(newBlockLinks) + sizeof(blockHeader); struct freeBlockLinks *prevBlock = INIT_STRUCT(freeBlockLinks, prev); NEXT_BLOCK(prevBlock) = newBlock; }
/* * mm_check - heap consistency checker. return 0 if something is wrong, 1 otherwise. */ int mm_check(void) { void *cur, *end; if(!rb_check_preorder()){ return 0; } cur = mem_heap_lo() + MIN_BLOCK_SIZE; end = mem_heap_hi() - 3; while(cur < end){ if(CUR_FREE(cur)){ // cur is free block if(PREV_FREE(cur)){ // contiguous free block printf("%p, %p are consecutive, but both are free.\n", PREV_BLOCK(cur, CUR_SIZE_MASKED(cur)), cur); return 0; } if(IS_IN_RB(cur) && !rb_find_exact(cur)){ // cur is not in Red-black tree printf("%p is free block, but is not in Red-black tree.\n", cur); return 0; } }else{ // cur is allocated block } cur = NEXT_BLOCK(cur, CUR_SIZE_MASKED(cur)); } return 1; }
// size in words. // Flag one means block is free. void initialiseFreeBlock(void* freeRegion, uint32_t size, void* prevFreeRegion, void* nextFreeRegion, bool flag, bool setHeader) { totalFreeSpace += WORDS_TO_BYTES(size); // Stats // Update largest free region. if (size > largestFreeBlock) { largestFreeBlock = WORDS_TO_BYTES(size); } if (setHeader) { struct blockHeader *header = INIT_STRUCT(blockHeader, freeRegion); header->attribute = size; // Set size. Size is max 2^30. Flag is 0 by default. if (flag) header->attribute |= MSB_TO_ONE; // Set flag to 1. } void* usableArea = ADDRESS_PLUS_OFFSET(freeRegion, blockHeader); struct freeBlockLinks *blockLinks = INIT_STRUCT(freeBlockLinks, usableArea); PREV_BLOCK(blockLinks) = prevFreeRegion; NEXT_BLOCK(blockLinks) = nextFreeRegion; // Set footer free region. uint64_t sizeOffset = WORDS_TO_BYTES(size); void* footer = ADDRESS_MINUS_OFFSET(usableArea + sizeOffset, freeBlockFooter); struct freeBlockFooter *blockFooter = INIT_STRUCT(freeBlockFooter, footer); blockFooter->size = size; }
// 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; }
// 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); } }
/* TBD: Make this function force inline */ static inline void prvInsertBlockIntoFreeList( xBlockLink * pxBlockToInsert ) { xBlockLink *pxIterator; xBlockLink *xBlockToMerge; size_t xBlockSize; ASSERT(IS_FREE_BLOCK(pxBlockToInsert)); /* We have a block which we are about to declare as a free block. * Lets find out if there is a free block in front of us and back * of us */ /* TRACE("pxBlockToInsert->pxNextFreeBlock: %x ->pxPrev = %x\n\r", pxBlockToInsert->pxNextFreeBlock, pxBlockToInsert->pxPrev); */ /* Check for front merge */ if ( !IS_LAST_BLOCK( pxBlockToInsert ) ) { if ( IS_FREE_BLOCK(NEXT_BLOCK( pxBlockToInsert ) ) ) { xBlockToMerge = NEXT_BLOCK( pxBlockToInsert ); /* Find out xBlockToMerge's location on the free list.*/ for( pxIterator = &xStart; pxIterator->pxNextFreeBlock != xBlockToMerge && pxIterator->pxNextFreeBlock != NULL; pxIterator = pxIterator->pxNextFreeBlock ) {} #ifdef DEBUG_HEAP if(! ( pxIterator->pxNextFreeBlock == xBlockToMerge ) ) { /* * This is not a good situation. The * problem is that data structures here are * showing that the next block is free. But * ths free block could not be found in the * free list. */ ATRACE("Target block dump :\n\r"); ATRACE("pxNextFreeBlock : 0x%x\n\r", xBlockToMerge->pxNextFreeBlock); ATRACE("pxPrev : 0x%x\n\r", xBlockToMerge->pxPrev); ATRACE("xBlockSize : %d (0x%x)\n\r", xBlockToMerge->xBlockSize, xBlockToMerge->xBlockSize); #ifdef DEBUG_HEAP_EXTRA ATRACE("xActualBlockSize: %d\n\r", xBlockToMerge->xActualBlockSize); #endif /* DEBUG_HEAP_EXTRA */ ATRACE("Panic\n\r"); while(1) {} } #endif /* DEBUG_HEAP */ ASSERT( pxIterator->pxNextFreeBlock == xBlockToMerge ); //TRACE("Merge: F\n\r"); /* Delete node from Free list */ pxIterator->pxNextFreeBlock = xBlockToMerge->pxNextFreeBlock; /* Delete xBlockToMerge node from Serial List */ if( ! IS_LAST_BLOCK( xBlockToMerge ) ) NEXT_BLOCK( xBlockToMerge )->pxPrev = pxBlockToInsert; /* Update node size */ pxBlockToInsert->xBlockSize += BLOCK_SIZE( xBlockToMerge ); /* Now forget about xBlockToMerge */ } } /* Check for back merge */ if ( ! IS_FIRST_BLOCK(pxBlockToInsert) ) { if ( IS_FREE_BLOCK( PREV_BLOCK(pxBlockToInsert ))) { xBlockToMerge = PREV_BLOCK(pxBlockToInsert); /* Find out xBlockToMerge's location on the free list */ for( pxIterator = &xStart; pxIterator->pxNextFreeBlock != xBlockToMerge && pxIterator->pxNextFreeBlock != NULL; pxIterator = pxIterator->pxNextFreeBlock ) {} ASSERT( pxIterator->pxNextFreeBlock == xBlockToMerge ); //TRACE("Merge: R\n\r"); /* Delete xBlockToMerge node from Free list */ pxIterator->pxNextFreeBlock = xBlockToMerge->pxNextFreeBlock; /* Delete _ pxBlockToInsert _ node from Serial List */ if( ! IS_LAST_BLOCK( pxBlockToInsert ) ) NEXT_BLOCK( pxBlockToInsert )->pxPrev = xBlockToMerge; /* Update node size */ xBlockToMerge->xBlockSize += BLOCK_SIZE( pxBlockToInsert ); /* Now forget about pxBlockToInsert */ pxBlockToInsert = xBlockToMerge; } } xBlockSize = pxBlockToInsert->xBlockSize; /* Iterate through the list until a block is found that has a larger size */ /* than the block we are inserting. */ for( pxIterator = &xStart; pxIterator->pxNextFreeBlock->xBlockSize < xBlockSize; pxIterator = pxIterator->pxNextFreeBlock ) { /* There is nothing to do here - just iterate to the correct position. */ } /* Update the list to include the block being inserted in the correct */ /* position. */ pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock; pxIterator->pxNextFreeBlock = pxBlockToInsert; }
/* * mm_free - Coalesce with surrounding blocks, and put it to Red-black tree */ void mm_free(void *ptr) { size_t size, new_size; void *prev, *cur, *next, *new_block; cur = ptr - HEADER_SIZE; /* double free */ if(CUR_FREE(cur)){ printf("try to free a freed memory block(%p) is detected.\n", cur); return ; } new_block = cur; new_size = CUR_SIZE_MASKED(cur); /* coalesce with the previous block if free */ if(PREV_FREE(cur)){ size = PREV_SIZE_MASKED(cur); prev = PREV_BLOCK(cur, size); if(IS_IN_RB(prev)){ rb_delete(prev); } new_block = prev; new_size += size; } /* coalesce with the next block if exists and free */ size = CUR_SIZE_MASKED(cur); next = NEXT_BLOCK(cur, size); if(next + 4 <= mem_heap_hi() && CUR_FREE(next)){ size = CUR_SIZE_MASKED(next); if(IS_IN_RB(next)){ rb_delete(next); } new_size += size; } /* new free block setting */ CUR_SIZE(new_block) = PREV_SIZE(NEXT_BLOCK(new_block, new_size)) = new_size | 1; if(IS_IN_RB(new_block)){ rb_insert(new_block); } #ifdef DEBUG printf("mm_free(%p) called\n", ptr); printf("new_block = %p\n", new_block); rb_print_preorder(); printf("\n"); #endif /* DEBUG */ #ifdef CHECK if(!mm_check()){ rb_print_preorder(); exit(0); } #endif /* CHECK */ /* DON't MODIFY THIS STAGE AND LEAVE IT AS IT WAS */ if (gl_ranges) remove_range(gl_ranges, ptr); }
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; }