/* * add_block - add a block to the list in order of address */ static void add_block(void *bp) { int list = get_list(GET_SIZE(HDRP(bp))); void *next = free_lists[list]; while (next != LIST_END) { /* Insert bp in middle of list, or beginning if prev(next) is NULL */ if (next > bp) { if (GET_PREV_FREE(next) == LIST_END) free_lists[list] = bp; /* Update list head */ else SET_NEXT_FREE(GET_PREV_FREE(next), bp); SET_PREV_FREE(bp, GET_PREV_FREE(next)); SET_PREV_FREE(next, bp); SET_NEXT_FREE(bp, next); return; /* Reached end of list, add bp to the end using saved block */ } else if (GET_NEXT_FREE(next) == LIST_END) { SET_PREV_FREE(bp, next); SET_NEXT_FREE(next, bp); SET_NEXT_FREE(bp, LIST_END); return; } next = GET_NEXT_FREE(next); } /* Edge case: list is empty, add bp */ SET_PREV_FREE(bp, LIST_END); SET_NEXT_FREE(bp, LIST_END); free_lists[list] = bp; }
/*Removes the free block pointer int the free_list*/ static void removeFromFree(void *bp){ if (GET_PREV_FREE(bp)) SET_NEXT_FREE(GET_PREV_FREE(bp), GET_NEXT_FREE(bp)); else free_listp = GET_NEXT_FREE(bp); SET_PREV_FREE(GET_NEXT_FREE(bp), GET_PREV_FREE(bp)); }
static void delete_free_block(void *ptr) { void *next_free = GET_NEXT_FREE(ptr); void *prev_free = GET_PREV_FREE(ptr); if (ptr == free_headp && ptr == free_tailp) { free_headp = NULL; free_tailp = NULL; } else if (ptr == free_headp) { free_headp = next_free; PUT_PREV_FREE(free_headp, NULL); } else if (ptr == free_tailp) { free_tailp = prev_free; PUT_NEXT_FREE(free_tailp, NULL); } else { PUT_NEXT_FREE(prev_free, next_free); PUT_PREV_FREE(next_free, prev_free); } }
/* * delete_block - delete a block from the free list */ static void delete_block(void *bp) { void *prev = GET_PREV_FREE(bp); void *next = GET_NEXT_FREE(bp); int list = get_list(GET_SIZE(HDRP(bp))); /* Case 1: bp is the only block in list */ if ((prev == LIST_END) && (next == LIST_END)) { free_lists[list] = NULL; return; /* Case 2: bp is the first block in the list */ } else if (prev == LIST_END) { SET_PREV_FREE(next, LIST_END); free_lists[list] = next; return; /* Case 3: bp is the last block in the list */ } else if (next == LIST_END) { SET_NEXT_FREE(prev, LIST_END); return; /* Case 4: bp is in the middle of the list */ } else { SET_NEXT_FREE(prev, next); SET_PREV_FREE(next, prev); return; } }
static void *find_fit(size_t asize){ void *bp; for (bp = free_listp; GET_ALLOC(HDRP(bp)) == 0; bp = GET_NEXT_FREE(bp) ){ if (asize <= (size_t)GET_SIZE(HDRP(bp)) ) { return bp; } } return NULL; }
/* * search_list - search the free list for a block of at least asize */ static void *search_list(size_t asize) { /* root of free list */ void* bp = free_list; /* traverse the free list */ while (bp != NULL) { if (GET_SIZE(HDRP(bp)) >= asize) return split(bp, asize); bp = GET_NEXT_FREE(bp); } /* No free block found */ return NULL; }
static void *find_fit(size_t size) { void * ptr = free_headp; while (ptr) { size_t bsize = GET_SIZE(HDRP(ptr)); mm_log("considering %p (%d)\n", ptr, (int)bsize); if (bsize >= size) return ptr; ptr = GET_NEXT_FREE(ptr); } return NULL; }
/* * search_list - search the free list for a block of at least asize */ static void *search_list(size_t asize) { /* root of smallest free list that fits asize */ int list = get_list(asize); void *bp = free_lists[list]; /* cycle through all lists with bucket size >= query size */ while (list < NUM_LISTS+1) { while (bp != NULL) { if (GET_SIZE(HDRP(bp)) >= asize) return split(bp, asize); bp = GET_NEXT_FREE(bp); } bp = free_lists[list++]; } /* No free block found */ return NULL; }
/* * mm_check - TODO */ static int mm_check() { /* Check that the blocks are properly organized & that epilogue is present */ void *ptr = heap_listp; int prev_alloced; int freecount = 0; while (ptr < mem_heap_hi()) { size_t size = GET_SIZE(HDRP(ptr)); size_t size2 = GET_SIZE(FTRP(ptr)); int allocated = GET_ALLOC(HDRP(ptr)); int allocated2 = GET_ALLOC(FTRP(ptr)); if (size == 0) { if (ptr != mem_heap_hi() - WSIZE) { mm_log("mm_check error: ran into size 0 (epilogue) at %p, which is not heap_hi().\n",ptr); return -1; } if (!allocated) { mm_log("mm_check error: epilogue at %p is marked as free\n",ptr); return -1; } } if (size != size2) { mm_log("mm_check error: %p size in header %d != footer %d\n", ptr, (int)size, (int)size2); return -1; } if (allocated != allocated2) { mm_log("mm_check error: %p alloc in header %d != footer %d\n", ptr, allocated, allocated2); return -1; } if (!allocated && !prev_alloced) { mm_log("mm_check error: two contiguous free blocks that should be coalesced. %p and prev.\n",ptr); } if (allocated) { //mm_log("block %p (%d,%d)\n", ptr, (int)size, allocated); } else { mm_log("block %p (%d,%d). prev=%p next=%p\n", ptr, (int)size, allocated, GET_PREV_FREE(ptr), GET_NEXT_FREE(ptr)); freecount++; } prev_alloced = allocated; ptr += size; } /* Check the free list */ int count = 0; ptr = free_headp; void *prev = NULL; while (ptr != NULL) { count++; size_t bsize = GET_SIZE(HDRP(ptr)); if (GET_NEXT_FREE(ptr) && GET_PREV_FREE(GET_NEXT_FREE(ptr)) != ptr) { mm_log("mm_check error: prev of next of %p is %p\n", ptr, GET_PREV_FREE(GET_NEXT_FREE(ptr))); return -1; } if (GET_PREV_FREE(ptr) && GET_NEXT_FREE(GET_PREV_FREE(ptr)) != ptr) { mm_log("mm_check error: next of prev of %p is %p\n", ptr, GET_NEXT_FREE(GET_PREV_FREE(ptr))); return -1; } if (bsize == 0) { mm_log("mm_check error: block size 0 at %p\n", ptr); return -1; } if (GET_ALLOC(HDRP(ptr)) || GET_ALLOC(FTRP(ptr))) { mm_log("mm_check error: block at %p on the freelist is marked allocated\n", ptr); return -1; } if (GET_PREV_FREE(ptr) != prev) { mm_log("mm_check error: block at %p does not point to prev %p (points to %p)\n", ptr, prev, GET_PREV_FREE(ptr)); return -1; } prev = ptr; ptr = GET_NEXT_FREE(ptr); } if (prev != free_tailp) { mm_log("mm_check error: last free block (%p) should == free_tailp (%p)\n", prev, free_tailp); return -1; } if (freecount != count) { mm_log("mm_check error: found %d free blocks, but only %d on the freelist.\n",freecount, count); return -1; } mm_log("mm_check says %d free block(s)\n",count); return 0; }
/* * mm_checkheap - Check the heap for correctness. It prints a nice grid * representation of the heap at the moment in time it is * called, as well as the block pointer and epilogue * pointer. It takes __LINE__ as input, allowing it to print * the number of the line it is called at. It also silently * checks for errors and exits the program if any error * is found. If silent is 0, it will only print the results * upon finding an error. * * NOTE: if mm_checkheap is called ANYWHERE besides malloc and * free, it will find errors because of intermediate states * that trigger error conditions. Therefore error_check should * be 0 if you call it anywhere besides inside malloc and free. */ void mm_checkheap(int lineno) { char *bp; char alloc_char; char aligned; char hef; int payload; int size; int num_head = 0, num_tail = 0; int link_error_flag = 0; int alignment_flag = 0; int error_flag = 0; int error_check = 1; /* set to 0 if called outside malloc() and free() */ int silent = 1; /* Silently check for errors */ if (error_check) { for (bp = heap_listp; GET_SIZE(HDRP(bp)) > 0; bp = NEXT_BLKP(bp)) { if (!ALIGNED(bp)) alignment_flag = 1; if (!GET_ALLOC(HDRP(bp))) { /* Check for linked list errors in free blocks */ if (GET_NEXT_FREE(bp) == NULL) num_tail++; else if (GET_PREV_FREE(GET_NEXT_FREE(bp)) != bp) link_error_flag = 1; if (GET_PREV_FREE(bp) == NULL) num_head++; else if (GET_NEXT_FREE(GET_PREV_FREE(bp)) != bp) link_error_flag = 1; } if (num_tail > 1||num_head > 1||link_error_flag||alignment_flag) error_flag = 1; } } if (error_flag || !silent) { printf("\n"); printf("========================================" "==========================================\n"); printf(" HEAP CONSISTENCY CHECKER\n"); printf("========================================" "==========================================\n"); printf("Line number = %d\n", lineno); printf("Head of free list = %p\n",free_list); printf("Epilogue pointer = %p\n", eptr); printf("----------------------------------------" "-----------------------------------------\n"); printf("T | Block pointer | Size |Payload|" " Prev | Next |A|HEF\n"); printf("--|------------------|-------|-------|--" "----------------|------------------|-|---\n"); for (bp = heap_listp; GET_SIZE(HDRP(bp)) > 0; bp = NEXT_BLKP(bp)) { payload = FTRP(bp)-bp; size = GET_SIZE(HDRP(bp)); alloc_char = ALLOC_CHAR(HDRP(bp)); aligned = ALIGNED_CHAR(bp); /* Check for alignment */ hef = HEF(bp); /* Check that header = footer */ if (GET_ALLOC(HDRP(bp))) { printf("%c |%18p|%7d|%7d|%18s|%18s|%c| %c \n", alloc_char, bp, size, payload, "", "", aligned, hef); } else { printf("%c |%18p|%7d|%7d|%18p|%18p|%c| %c \n", alloc_char, bp, size, payload, GET_PREV_FREE(bp), GET_NEXT_FREE(bp), aligned, hef); } } printf("----------------------------------------" "-----------------------------------------\n"); printf("Key: T = (a)llocated or (f)ree. A = aligned to double word." " HEF = H/F tags match.\n"); /* If there is a problem with the free list, print details and exit. */ if (error_flag) { printf("----------------------------------------" "-----------------------------------------\n"); printf("Heap integrity errors found:\n"); if (num_tail > 1) printf(" [List error] More than one list tail.\n"); if (num_head > 1) printf(" [List error] More than one list head.\n"); if (link_error_flag) printf(" [List error] Links don't match up in " "at least one block.\n"); if (alignment_flag) printf(" [Alignment error] Unaligned block detected.\n"); printf("----------------------------------------" "-----------------------------------------\n"); printf("\n"); exit(0); } } }