/* * mm-implicit.c - Simple allocator based on implicit free lists, * first fit placement, and boundary tag coalescing. * * Each block has header and footer of the form: * * 31 3 2 1 0 * ----------------------------------- * | s s s s ... s s s 0 0 a/f * ----------------------------------- * * where s are the meaningful size bits and a/f is set * iff the block is allocated. The list has the following form: * * begin end * heap heap * ----------------------------------------------------------------- * | pad | hdr(8:a) | ftr(8:a) | zero or more usr blks | hdr(8:a) | * ----------------------------------------------------------------- * | prologue | | epilogue | * | block | | block | * * The allocated prologue and epilogue blocks are overhead that * eliminate edge conditions during coalescing. */ #include #include #include #include #include "mm.h" #include "memlib.h" /* * If NEXT_FIT defined use next fit search, else use first fit search */ #define NEXT_FITx /* Team structure */ team_t team = { #ifdef NEXT_FIT "implicit next fit", #else "implicit first fit", #endif "Dave OHallaron", "droh", "", "" }; /* $begin mallocmacros */ /* Basic constants and macros */ #define WSIZE 4 /* word size (bytes) */ #define DSIZE 8 /* doubleword size (bytes) */ #define CHUNKSIZE (1<<12) /* initial heap size (bytes) */ #define OVERHEAD 8 /* overhead of header and footer (bytes) */ #define MAX(x, y) ((x) > (y)? (x) : (y)) /* Pack a size and allocated bit into a word */ #define PACK(size, alloc) ((size) | (alloc)) /* Read and write a word at address p */ #define GET(p) (*(size_t *)(p)) #define PUT(p, val) (*(size_t *)(p) = (val)) /* Read the size and allocated fields from address p */ #define GET_SIZE(p) (GET(p) & ~0x7) #define GET_ALLOC(p) (GET(p) & 0x1) /* Given block ptr bp, compute address of its header and footer */ #define HDRP(bp) ((char *)(bp) - WSIZE) #define FTRP(bp) ((char *)(bp) + GET_SIZE(HDRP(bp)) - DSIZE) /* Given block ptr bp, compute address of next and previous blocks */ #define NEXT_BLKP(bp) ((char *)(bp) + GET_SIZE(((char *)(bp) - WSIZE))) #define PREV_BLKP(bp) ((char *)(bp) - GET_SIZE(((char *)(bp) - DSIZE))) /* $end mallocmacros */ /* Global variables */ static char *heap_listp; /* pointer to first block */ #ifdef NEXT_FIT static char *rover; /* next fit rover */ #endif /* function prototypes for internal helper routines */ static void *extend_heap(size_t words); static void place(void *bp, size_t asize); static void *find_fit(size_t asize); static void *coalesce(void *bp); static void printblock(void *bp); static void checkblock(void *bp); /* * mm_init - Initialize the memory manager */ /* $begin mminit */ int mm_init(void) { /* create the initial empty heap */ if ((heap_listp = mem_sbrk(4*WSIZE)) == NULL) return -1; PUT(heap_listp, 0); /* alignment padding */ PUT(heap_listp+WSIZE, PACK(OVERHEAD, 1)); /* prologue header */ PUT(heap_listp+DSIZE, PACK(OVERHEAD, 1)); /* prologue footer */ PUT(heap_listp+WSIZE+DSIZE, PACK(0, 1)); /* epilogue header */ heap_listp += DSIZE; #ifdef NEXT_FIT rover = heap_listp; #endif /* Extend the empty heap with a free block of CHUNKSIZE bytes */ if (extend_heap(CHUNKSIZE/WSIZE) == NULL) return -1; return 0; } /* $end mminit */ /* * mm_malloc - Allocate a block with at least size bytes of payload */ /* $begin mmmalloc */ void *mm_malloc(size_t size) { size_t asize; /* adjusted block size */ size_t extendsize; /* amount to extend heap if no fit */ char *bp; /* Ignore spurious requests */ if (size <= 0) return NULL; /* Adjust block size to include overhead and alignment reqs. */ if (size <= DSIZE) asize = DSIZE + OVERHEAD; else asize = DSIZE * ((size + (OVERHEAD) + (DSIZE-1)) / DSIZE); /* Search the free list for a fit */ if ((bp = find_fit(asize)) != NULL) { place(bp, asize); return bp; } /* No fit found. Get more memory and place the block */ extendsize = MAX(asize,CHUNKSIZE); if ((bp = extend_heap(extendsize/WSIZE)) == NULL) return NULL; place(bp, asize); return bp; } /* $end mmmalloc */ /* * mm_free - Free a block */ /* $begin mmfree */ void mm_free(void *bp) { size_t size = GET_SIZE(HDRP(bp)); PUT(HDRP(bp), PACK(size, 0)); PUT(FTRP(bp), PACK(size, 0)); coalesce(bp); } /* $end mmfree */ /* * mm_realloc - naive implementation of mm_realloc */ void *mm_realloc(void *ptr, size_t size) { void *newp; size_t copySize; if ((newp = mm_malloc(size)) == NULL) { printf("ERROR: mm_malloc failed in mm_realloc\n"); exit(1); } copySize = GET_SIZE(HDRP(ptr)); if (size < copySize) copySize = size; memcpy(newp, ptr, copySize); mm_free(ptr); return newp; } /* * mm_checkheap - Check the heap for consistency */ void mm_checkheap(int verbose) { char *bp = heap_listp; if (verbose) printf("Heap (%p):\n", heap_listp); if ((GET_SIZE(HDRP(heap_listp)) != DSIZE) || !GET_ALLOC(HDRP(heap_listp))) printf("Bad prologue header\n"); checkblock(heap_listp); for (bp = heap_listp; GET_SIZE(HDRP(bp)) > 0; bp = NEXT_BLKP(bp)) { if (verbose) printblock(bp); checkblock(bp); } if (verbose) printblock(bp); if ((GET_SIZE(HDRP(bp)) != 0) || !(GET_ALLOC(HDRP(bp)))) printf("Bad epilogue header\n"); } /* The remaining routines are internal helper routines */ /* * extend_heap - Extend heap with free block and return its block pointer */ /* $begin mmextendheap */ static void *extend_heap(size_t words) { char *bp; size_t size; /* Allocate an even number of words to maintain alignment */ size = (words % 2) ? (words+1) * WSIZE : words * WSIZE; if ((bp = mem_sbrk(size)) == (void *)-1) return NULL; /* Initialize free block header/footer and the epilogue header */ PUT(HDRP(bp), PACK(size, 0)); /* free block header */ PUT(FTRP(bp), PACK(size, 0)); /* free block footer */ PUT(HDRP(NEXT_BLKP(bp)), PACK(0, 1)); /* new epilogue header */ /* Coalesce if the previous block was free */ return coalesce(bp); } /* $end mmextendheap */ /* * place - Place block of asize bytes at start of free block bp * and split if remainder would be at least minimum block size */ /* $begin mmplace */ /* $begin mmplace-proto */ static void place(void *bp, size_t asize) /* $end mmplace-proto */ { size_t csize = GET_SIZE(HDRP(bp)); if ((csize - asize) >= (DSIZE + OVERHEAD)) { PUT(HDRP(bp), PACK(asize, 1)); PUT(FTRP(bp), PACK(asize, 1)); bp = NEXT_BLKP(bp); PUT(HDRP(bp), PACK(csize-asize, 0)); PUT(FTRP(bp), PACK(csize-asize, 0)); } else { PUT(HDRP(bp), PACK(csize, 1)); PUT(FTRP(bp), PACK(csize, 1)); } } /* $end mmplace */ /* * find_fit - Find a fit for a block with asize bytes */ static void *find_fit(size_t asize) { #ifdef NEXT_FIT /* next fit search */ char *oldrover = rover; /* search from the rover to the end of list */ for ( ; GET_SIZE(HDRP(rover)) > 0; rover = NEXT_BLKP(rover)) if (!GET_ALLOC(HDRP(rover)) && (asize <= GET_SIZE(HDRP(rover)))) return rover; /* search from start of list to old rover */ for (rover = heap_listp; rover < oldrover; rover = NEXT_BLKP(rover)) if (!GET_ALLOC(HDRP(rover)) && (asize <= GET_SIZE(HDRP(rover)))) return rover; return NULL; /* no fit found */ #else /* first fit search */ void *bp; for (bp = heap_listp; GET_SIZE(HDRP(bp)) > 0; bp = NEXT_BLKP(bp)) { if (!GET_ALLOC(HDRP(bp)) && (asize <= GET_SIZE(HDRP(bp)))) { return bp; } } return NULL; /* no fit */ #endif } /* * coalesce - boundary tag coalescing. Return ptr to coalesced block */ static void *coalesce(void *bp) { size_t prev_alloc = GET_ALLOC(HDRP(PREV_BLKP(bp))); size_t next_alloc = GET_ALLOC(HDRP(NEXT_BLKP(bp))); size_t size = GET_SIZE(HDRP(bp)); /*四种情况*/ if (prev_alloc && next_alloc) /*case1*/ { return bp; } else if (prev_alloc && !next_alloc) /*case2*/ { size += GET_SIZE(HDRP(NEXT_BLKP(bp))); PUT(HDRP(bp), PACK(size, 0)); PUT(FTRP(bp), PACK(size, 0)); } else if (!prev_alloc && next_alloc) /*case3*/ { size += GET_SIZE(HDRP(PREV_BLKP(bp))); PUT(FTRP(bp), PACK(size, 0)); PUT(HDRP(PREV_BLKP(bp)), PACK(size, 0)); bp = PREV_BLKP(bp); } else /*case4*/ { size += GET_SIZE(HDRP(PREV_BLKP(bp))) + GET_SIZE(HDRP(NEXT_BLKP(bp))); PUT(HDRP(PREV_BLKP(bp)), PACK(size, 0)); PUT(FTRP(NEXT_BLKP(bp)), PACK(size, 0)); bp = PREV_BLKP(bp); } return bp; } static void printblock(void *bp) { size_t hsize, halloc, fsize, falloc; hsize = GET_SIZE(HDRP(bp)); halloc = GET_ALLOC(HDRP(bp)); fsize = GET_SIZE(FTRP(bp)); falloc = GET_ALLOC(FTRP(bp)); if (hsize == 0) { printf("%p: EOL\n", bp); return; } printf("%p: header: [%d:%c] footer: [%d:%c]\n", bp, hsize, (halloc ? 'a' : 'f'), fsize, (falloc ? 'a' : 'f')); } static void checkblock(void *bp) { if ((size_t)bp % 8) printf("Error: %p is not doubleword aligned\n", bp); if (GET(HDRP(bp)) != GET(FTRP(bp))) printf("Error: header does not match footer\n"); }