/*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)); }
/* * 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; }
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; } }
/* * Scan the heap until we find a block large enough to fulfill the * request. */ void * malloc(unsigned sz) { block_header_t *header, *next; /* Align the request. */ sz += MIN_REQUEST - 1; sz &= ~(MIN_REQUEST - 1); /* First fit. */ for (header = (block_header_t *) heap_start; (char *) header < heap_end; header = next) { next = (block_header_t *) ((char *) header + sizeof(block_header_t) + GET_BLOCK_SIZE(*header)); if (GET_PREV_FREE(*next) && sz <= GET_BLOCK_SIZE(*header)) { /* We can fit the request in this block. */ void *result = (void *)((char *) header + sizeof(block_header_t)); if (GET_BLOCK_SIZE(*header) < sz + sizeof(block_header_t) + MIN_REQUEST) { /* We can't fit any other requests here, though. */ CLEAR_PREV_FREE(*next); } else { /* Split the block. */ struct block_footer *footer = (struct block_footer *) ((char *) next - sizeof(struct block_footer)); unsigned remaining = GET_BLOCK_SIZE(*header) - sz - sizeof(block_header_t); SET_BLOCK_SIZE(*header, sz); header = (block_header_t *) ((char *) header + sizeof(block_header_t) + sz); ASSERT(remaining % 2 == 0, ("odd block size")); INIT_BLOCK_HEADER(*header, remaining, 0); footer->header = header; } return result; } } /* Uh oh, couldn't allocate! */ panic(); return 0; }
/* * Free the block, coalescing with the previous and next blocks if * possible. */ void free(void *ptr) { block_header_t *header = (block_header_t *) ((char *) ptr - sizeof(block_header_t)); block_header_t *next = (block_header_t *) ((char *) ptr + GET_BLOCK_SIZE(*header)); block_header_t *next_next = (block_header_t *) ((char *) next + sizeof(block_header_t) + GET_BLOCK_SIZE(*next)); struct block_footer *footer; unsigned size; if ((char *) next_next < heap_end && GET_PREV_FREE(*next_next)) { /* The block following us is free. */ next = next_next; } if (GET_PREV_FREE(*header)) { /* The block prior to us is free. */ footer = (struct block_footer *) ((char *) header - sizeof(struct block_footer)); header = footer->header; } footer = (struct block_footer *) ((char *) next - sizeof(struct block_footer)); footer->header = header; /* Expand the block to encompass the reclaimed space. */ size = (char *) next - (char *) header - sizeof(block_header_t); ASSERT(size % 2 == 0, ("odd block size")); SET_BLOCK_SIZE(*header, size); /* Note in the header of the _next_ block that this block is free. */ MARK_PREV_FREE(*next); }
/* * Dump the heap to debug it. */ void heap_walk() { block_header_t *header, *next; printf("heap_begin=0x%p, heap_end=0x%p\n", heap_start, heap_end); for (header = (block_header_t *) heap_start; (char *) header < heap_end; header = next) { next = (block_header_t *) ((char *) header + sizeof(block_header_t) + GET_BLOCK_SIZE(*header)); printf("%p heap_start+%04x size=%04x %s", header, (char *) header - heap_start, GET_BLOCK_SIZE(*header), GET_PREV_FREE(*next) ? "free" : "in use"); if (GET_PREV_FREE(*next)) { struct block_footer *footer = (struct block_footer *) ((char *) next - sizeof(struct block_footer)); if (footer->header != header) { printf(" BAD FOOTER, footer->header=%p heap_start+%04x", footer->header, (char *) footer->header - heap_start); } } printf("\n"); } }
/* * Return the amount of free space in the heap. */ int heap_free() { int nfree = 0; block_header_t *header, *next; for (header = (block_header_t *) heap_start; (char *) header < heap_end; header = next) { next = (block_header_t *) ((char *) header + sizeof(block_header_t) + GET_BLOCK_SIZE(*header)); if (GET_PREV_FREE(*next)) nfree += GET_BLOCK_SIZE(*header); } return nfree; }
/* * 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); } } }