diff --git a/mm.c b/mm.c index c831db1..db02a33 100644 --- a/mm.c +++ b/mm.c @@ -25,6 +25,8 @@ struct block { struct list_elem elem; }; +static struct block *heap_listp = 0; + /* Basic constants and macros */ #define WSIZE sizeof(struct boundary_tag) /* Word and header/footer size (bytes) */ #define DSIZE 2*WSIZE @@ -50,16 +52,34 @@ static size_t list_sizes[NUM_LISTS]; /* Function prototypes for internal helper routines */ static struct block *extend_heap(size_t words, int realloc); static void place(struct block *blck, size_t asize); -static struct list* find_list(int not_empty, size_t size); +static struct list* find_list(size_t size); static struct block *find_fit(size_t num_words); +//~ static void coalesce_free_lists(); +static struct block *coalesce(struct block *bp); + +/* Given a block, obtain previous's block footer. + Works for left-most block also. */ +static struct boundary_tag * prev_blk_footer(struct block *blk) { + return &blk->header - 1; +} + +/* Return if block is free */ +static bool blk_free(struct block *blk) { + return !blk->header.inuse; +} /* Return size of block is free */ static size_t blk_size(struct block *blk) { return blk->header.size; } - - +/* Given a block, obtain pointer to previous block. + Not meaningful for left-most block. */ +static struct block *prev_blk(struct block *blk) { + struct boundary_tag *prevfooter = prev_blk_footer(blk); + assert(prevfooter->size != 0); + return (struct block *)((void *)blk - WSIZE * prevfooter->size); +} /* Given a block, obtain pointer to next block. Not meaningful for right-most block. */ @@ -95,6 +115,41 @@ static void set_block_free(struct block *blk, int size) { set_header_and_footer(blk, size, 0); } +int mm_init(void) +{ + assert (offsetof(struct block, payload) == 4); + assert (sizeof(struct boundary_tag) == 4); + + /* Create the initial empty heap */ + struct boundary_tag * initial = mem_sbrk(4 * sizeof(struct boundary_tag)); + if (initial == NULL) + return -1; + + /* We use a slightly different strategy than suggested in the book. + * Rather than placing a min-sized prologue block at the beginning + * of the heap, we simply place two fences. + * The consequence is that coalesce() must call prev_blk_footer() + * and not prev_blk() because prev_blk() cannot be called on the + * left-most block. + */ + initial[2] = FENCE; /* Prologue footer */ + heap_listp = (struct block *)&initial[3]; + initial[3] = FENCE; /* Epilogue header */ + + for (int i = 0; i < NUM_LISTS; i++) { + struct list current_list; + list_init(¤t_list); + free_lists[i] = current_list; + } + + for (int i = 0; i < NUM_LISTS; i++) + list_sizes[i] = MIN_BLOCK_SIZE_WORDS * (i + 1); + + /* Extend the empty heap with a free block of CHUNKSIZE bytes */ + if (extend_heap(CHUNKSIZE, 1) == NULL) + return -1; + return 0; +} /* * The mm malloc routine returns a pointer to an allocated block payload of at @@ -115,6 +170,12 @@ void *mm_malloc(size_t size) { place(blck, words); return blck->payload; } + + //~ coalesce_free_lists(); + //~ if ((blck = find_fit(words)) != NULL) { + //~ place(blck, words); + //~ return blck->payload; + //~ } if ((blck = extend_heap(words, 0)) == NULL){ return NULL; @@ -123,7 +184,75 @@ void *mm_malloc(size_t size) { return blck->payload; } +void mm_free(void *bp) +{ + assert (heap_listp != 0); // assert that mm_init was called + if (bp == 0) + return; + /* Find block from user pointer */ + struct block *blk = bp - offsetof(struct block, payload); + size_t size = blk_size(blk); + + set_block_free(blk, size); + + list_push_front(find_list(size), &blk->elem); + + coalesce(blk); +} + +//~ static void coalesce_free_lists() +//~ { + //~ for (int i = 0; i < NUM_LISTS; i++) { + //~ struct list* current_list = &free_lists[i]; + //~ for (struct list_elem* e = list_begin(current_list); e != list_back(current_list); e = list_next(e)) { + //~ struct block* bp = list_entry(e, struct block, elem); + //~ coalesce(bp); + //~ } + //~ } +//~ } + +static struct block *coalesce(struct block *bp) +{ + bool prev_alloc = prev_blk_footer(bp)->inuse; /* is previous block allocated? */ + bool next_alloc = ! blk_free(next_blk(bp)); /* is next block allocated? */ + size_t size = blk_size(bp); + + if (prev_alloc && next_alloc) { /* Case 1 */ + // both are allocated, nothing to coalesce + return bp; + } + + else if (prev_alloc && !next_alloc) { /* Case 2 */ + // combine this block and next block by extending it + list_remove(&bp->elem); + set_block_free(bp, size + blk_size(next_blk(bp))); + list_remove(&next_blk(bp)->elem); + list_push_front(find_list(size + blk_size(next_blk(bp))), &bp->elem); + } + + else if (!prev_alloc && next_alloc) { /* Case 3 */ + // combine previous and this block by extending previous + list_remove(&bp->elem); + bp = prev_blk(bp); + set_block_free(bp, size + blk_size(bp)); + list_remove(&bp->elem); + list_push_front(find_list(size + blk_size(next_blk(bp))), &bp->elem); + + } + + else { /* Case 4 */ + // combine all previous, this, and next block into one + list_remove(&bp->elem); + set_block_free(prev_blk(bp), + size + blk_size(next_blk(bp)) + blk_size(prev_blk(bp))); + bp = prev_blk(bp); + list_remove(&bp->elem); + list_remove(&next_blk(bp)->elem); + list_push_front(find_list(size + blk_size(next_blk(bp))), &bp->elem); + } + return bp; +} /* * Extend heap with free block and return its block pointer @@ -144,7 +273,7 @@ static struct block *extend_heap(size_t words, int realloc) if (realloc) { return blk; } - list_push_front(find_list(0, words), &blk->elem); + list_push_front(find_list(words), &blk->elem); // NOT IMPLEMENTED YET //return coalesce(blk); @@ -168,7 +297,7 @@ static void place(struct block *blck, size_t asize) { set_block_free(blck, remaining_size); /* Add remaining free block back into list */ - list_push_front(find_list(0, remaining_size), &blck->elem); + list_push_front(find_list(remaining_size), &blck->elem); } else { set_block_used(blck, csize); @@ -178,11 +307,11 @@ static void place(struct block *blck, size_t asize) { /** * Find free list with blocks of given size */ -static struct list* find_list(int not_empty, size_t n_words) { +static struct list* find_list(size_t n_words) { for (int i = 0; i < NUM_LISTS; i++) { if ((n_words < list_sizes[i]) || (i == (NUM_LISTS - 1))) { - if (not_empty && list_empty(&free_lists[i])) { + if (list_empty(&free_lists[i])) { continue; } return &free_lists[i]; @@ -196,7 +325,7 @@ static struct list* find_list(int not_empty, size_t n_words) { */ static struct block *find_fit(size_t num_words) { - struct list* free_list = find_list(1, num_words); + struct list* free_list = find_list(num_words); if (free_list == NULL) { return NULL; @@ -212,5 +341,10 @@ static struct block *find_fit(size_t num_words) return NULL; } - - +team_t team = { + "?", // team name + "Micah Moore", + "micahmoore@vt.edu", + "Felicia Seo", + "seofelicia@vt.edu", +};