/* * mm_free - Free a block by adding it to the appropriate list and coalescing * it. */ void mm_free(void *ptr) { size_t size = GET_SIZE(HEAD(ptr)); /* Size of block */ /* Unset the reallocation tag on the next block */ UNSET_TAG(HEAD(NEXT(ptr))); /* Adjust the allocation status in boundary tags */ PUT(HEAD(ptr), PACK(size, 0)); PUT(FOOT(ptr), PACK(size, 0)); /* Insert new block into appropriate list */ insert_node(ptr, size); /* Coalesce free block */ coalesce(ptr); /* // Check heap for consistency line_count++; if (CHECK && CHECK_FREE) { mm_check('f', ptr, size); } */ return; }
/* * mark - mark a block's header and footer */ static inline void mark(void *bp, size_t block_size, int is_prev_alloc, int is_alloc) { is_prev_alloc = !!is_prev_alloc; is_alloc = !!is_alloc; PUT(HEAD(bp), PACK(block_size, is_prev_alloc, is_alloc)); if (!is_alloc) { PUT(FOOT(bp), PACK(block_size, is_prev_alloc, is_alloc)); } }
/* * mm_realloc - Reallocate a block in place, extending the heap if necessary. * The new block is padded with a buffer to guarantee that the * next reallocation can be done without extending the heap, * assuming that the block is expanded by a constant number of bytes * per reallocation. * * If the buffer is not large enough for the next reallocation, * mark the next block with the reallocation tag. Free blocks * marked with this tag cannot be used for allocation or * coalescing. The tag is cleared when the marked block is * consumed by reallocation, when the heap is extended, or when * the reallocated block is freed. */ void *mm_realloc(void *ptr, size_t size) { void *new_ptr = ptr; /* Pointer to be returned */ size_t new_size = size; /* Size of new block */ int remainder; /* Adequacy of block sizes */ int extendsize; /* Size of heap extension */ int block_buffer; /* Size of block buffer */ /* Filter invalid block size */ if (size == 0) return NULL; /* Adjust block size to include boundary tag and alignment requirements */ if (new_size <= DSIZE) { new_size = 2 * DSIZE; } else { new_size = DSIZE * ((new_size + (DSIZE) + (DSIZE - 1)) / DSIZE); } /* Add overhead requirements to block size */ new_size += BUFFER; /* Calculate block buffer */ block_buffer = GET_SIZE(HEAD(ptr)) - new_size; /* Allocate more space if overhead falls below the minimum */ if (block_buffer < 0) { /* Check if next block is a free block or the epilogue block */ if (!GET_ALLOC(HEAD(NEXT(ptr))) || !GET_SIZE(HEAD(NEXT(ptr)))) { remainder = GET_SIZE(HEAD(ptr)) + GET_SIZE(HEAD(NEXT(ptr))) - new_size; if (remainder < 0) { extendsize = MAX(-remainder, CHUNKSIZE); if (extend_heap(extendsize) == NULL) return NULL; remainder += extendsize; } delete_node(NEXT(ptr)); // Do not split block PUT_NOTAG(HEAD(ptr), PACK(new_size + remainder, 1)); /* Block header */ PUT_NOTAG(FOOT(ptr), PACK(new_size + remainder, 1)); /* Block footer */ } else { new_ptr = mm_malloc(new_size - DSIZE); //line_count--; memmove(new_ptr, ptr, MIN(size, new_size)); mm_free(ptr); //line_count--; } block_buffer = GET_SIZE(HEAD(new_ptr)) - new_size; } /* Tag the next block if block overhead drops below twice the overhead */ if (block_buffer < 2 * BUFFER) SET_TAG(HEAD(NEXT(new_ptr))); /* // Check heap for consistency line_count++; if (CHECK && CHECK_REALLOC) { mm_check('r', ptr, size); } */ /* Return reallocated block */ return new_ptr; }
/* * coalesce - Coalesce adjacent free blocks. Sort the new free block into the * appropriate list. */ static void *coalesce(void *ptr) { size_t prev_alloc = GET_ALLOC(HEAD(PREV(ptr))); size_t next_alloc = GET_ALLOC(HEAD(NEXT(ptr))); size_t size = GET_SIZE(HEAD(ptr)); /* Return if previous and next blocks are allocated */ if (prev_alloc && next_alloc) { return ptr; } /* Do not coalesce with previous block if it is tagged */ if (GET_TAG(HEAD(PREV(ptr)))) prev_alloc = 1; /* Remove old block from list */ delete_node(ptr); /* Detect free blocks and merge, if possible */ if (prev_alloc && !next_alloc) { delete_node(NEXT(ptr)); size += GET_SIZE(HEAD(NEXT(ptr))); PUT(HEAD(ptr), PACK(size, 0)); PUT(FOOT(ptr), PACK(size, 0)); } else if (!prev_alloc && next_alloc) { delete_node(PREV(ptr)); size += GET_SIZE(HEAD(PREV(ptr))); PUT(FOOT(ptr), PACK(size, 0)); PUT(HEAD(PREV(ptr)), PACK(size, 0)); ptr = PREV(ptr); } else { delete_node(PREV(ptr)); delete_node(NEXT(ptr)); size += GET_SIZE(HEAD(PREV(ptr))) + GET_SIZE(HEAD(NEXT(ptr))); PUT(HEAD(PREV(ptr)), PACK(size, 0)); PUT(FOOT(NEXT(ptr)), PACK(size, 0)); ptr = PREV(ptr); } /* Adjust segregated linked lists */ insert_node(ptr, size); return ptr; }
/* * place - Set headers and footers for newly allocated blocks. Split blocks * if enough space is remaining. */ static void place(void *ptr, size_t asize) { size_t ptr_size = GET_SIZE(HEAD(ptr)); size_t remainder = ptr_size - asize; /* Remove block from list */ delete_node(ptr); if (remainder >= MINSIZE) { /* Split block */ PUT(HEAD(ptr), PACK(asize, 1)); /* Block header */ PUT(FOOT(ptr), PACK(asize, 1)); /* Block footer */ PUT_NOTAG(HEAD(NEXT(ptr)), PACK(remainder, 0)); /* Next header */ PUT_NOTAG(FOOT(NEXT(ptr)), PACK(remainder, 0)); /* Next footer */ insert_node(NEXT(ptr), remainder); } else { /* Do not split block */ PUT(HEAD(ptr), PACK(ptr_size, 1)); /* Block header */ PUT(FOOT(ptr), PACK(ptr_size, 1)); /* Block footer */ } return; }
/* * extend_heap - Extend the heap with a system call. Insert the newly * requested free block into the appropriate list. */ static void *extend_heap(size_t size) { void *ptr; /* Pointer to newly allocated memory */ size_t words = size / WSIZE; /* Size of extension in words */ size_t asize; /* Adjusted size */ /* Allocate an even number of words to maintain alignment */ asize = (words % 2) ? (words + 1) * WSIZE : words * WSIZE; /* Extend the heap */ if ((long)(ptr = mem_sbrk(asize)) == -1) return NULL; /* Set headers and footer */ PUT_NOTAG(HEAD(ptr), PACK(asize, 0)); /* Free block header */ PUT_NOTAG(FOOT(ptr), PACK(asize, 0)); /* Free block footer */ PUT_NOTAG(HEAD(NEXT(ptr)), PACK(0, 1)); /* Epilogue header */ /* Insert new block into appropriate list */ insert_node(ptr, asize); /* Coalesce if the previous block was free */ return coalesce(ptr); }
/* * mm_checkheap */ void mm_checkheap(int verbose){ void *bp; unsigned *list_p; unsigned *pred, *succ; int i; if (!verbose) { return; } bp = data_head + DSIZE; /* checking the heap */ /* prologue */ if (!(block_size(bp) == 8 && block_alloc(bp) == 1)) { printf("Invariant Error: prologue block\n"); } /* blocks */ bp = next_block(bp); while (block_size(bp) != 0) { if ((long)bp % DSIZE != 0) { printf("Invariant Error: block's address isn't aligned\n"); } if (!block_alloc(bp)) { if (*(int *)HEAD(bp) != *(int *)FOOT(bp)) { printf("Invariant Error: block head and foot don't match\n"); } } if (!block_prev_alloc(bp)) { if (block_prev_alloc(bp) != block_alloc(prev_block(bp))) { printf("Invariant Error: prev alloc bit doesn't match prev block\n"); } if (block_alloc(bp) == 0) { printf("Inveriant Error: find consecutive free blocks\n"); } } if (block_alloc(bp) == 0 && block_alloc(next_block(bp)) == 0) { printf("Inveriant Error: find consecutive free blocks\n"); } if (block_size(bp) < 4 * WSIZE) { printf("Invariant Error: block is too small\n"); } bp = next_block(bp); } /* epilogue */ if (!(block_size(bp) == 0 && block_alloc(bp) == 1)) { printf("Invariant Error: epilogue block\n"); } /* checking the free list */ list_p = (unsigned *)heap_head; for (i = 0; i < ARRAYSIZE; i++) { if (!*list_p) { continue; } bp = (unsigned *)r2a((size_t)*list_p); while (bp != NULL) { pred = pred_block(bp); succ = succ_block(bp); if (pred != NULL) { if (*(pred + 1) != a2r((size_t)bp)) { printf("Invariant Error: inconsistent pointer\n"); } } if (succ != NULL) { if (*succ != a2r((size_t)bp)) { printf("Invariant Error: inconsistent pointer\n"); } } if (get_list(block_size((void *)bp)) != list_p) { printf("Invariant Error: block size doesn't match list\n"); } bp = succ; } list_p++; } print_heap(); }
void f() { FOOT(); //FOOT_KEEPER(__FUNCTION__); }