diff --git a/mm.c b/mm.c index 5fc52dff93cbe2712f192b38f96cd54d78468400..20f2d3bffc0ae6e1eb1f3e6998e36cd8d7647d72 100644 --- a/mm.c +++ b/mm.c @@ -85,6 +85,7 @@ static void place(void *bp, size_t asize); static void *find_fit(size_t asize); static void printblock(void *bp); static void mm_coalesce(void *bp); +static void mm_memcpy(void * dest, void * src); /* * mm_init - Initialize the memory manager @@ -151,7 +152,7 @@ void *mm_malloc(size_t size) place(bp, asize); - //mm_checkheap(1); + mm_checkheap(0); return bp; } @@ -177,6 +178,7 @@ void mm_free(void *bp) } else { fprintf(stderr, "Error: memory not alloced or corrupted"); } + mm_checkheap(0); } @@ -188,30 +190,32 @@ void mm_free(void *bp) * Given a block pointer that has been freed, find empty * blocks near it to be combined into a large free chunk. * - * TODO: coalesce previous chunks */ static void mm_coalesce(void *bp) { - //find next block - unsigned int nSize = 0; - if (GET_ALLOC(HDRP(NEXT_BLKP(bp)))) { - nSize = GET_SIZE(NEXT_BLKP(bp)); - } //find previous block char * prev; - unsigned int pSize = 0; for (prev = heap_listp; GET_SIZE(prev-WSIZE) > 0; prev = NEXT_BLKP(prev)) { - if (GET_ALLOC(HDRP(prev)) && NEXT_BLKP(prev) == bp) { - pSize = GET_SIZE(HDRP(prev)); + if (NEXT_BLKP(prev) == bp) { break; } } - if(pSize > 0){ - PUT(prev, PACK( pSize + nSize + GET_SIZE(HDRP(bp)), 1)); + size_t nextBlock = GET_ALLOC(HDRP(NEXT_BLKP(bp))); + size_t prevBlock = GET_ALLOC(HDRP(prev)); + size_t size = GET_SIZE(HDRP(bp)); + + if(prevBlock && nextBlock){ + size += GET_SIZE(HDRP(prev)) + GET_SIZE(HDRP(NEXT_BLKP(bp))); + PUT(HDRP(prev), PACK(size, 1)); + return; + } else if(prevBlock && !nextBlock){ + size += GET_SIZE(HDRP(prev)); + PUT(HDRP(prev), PACK(size, 1)); return; - } else if(nSize > 0){ - PUT(bp, PACK(nSize + GET_SIZE(HDRP(bp)), 1)); + } else if(!prevBlock && nextBlock){ + size += GET_SIZE(HDRP(NEXT_BLKP(bp))); + PUT(HDRP(bp), PACK(size, 1)); return; } } @@ -225,10 +229,107 @@ static void mm_coalesce(void *bp) */ void *mm_realloc(void *ptr, size_t size) { - + /** + * 1. if ptr is NULL, the call is equivalent to mm malloc(size); + * 2. if size is equal to zero, the call is equivalent to mm free(ptr); + * 3. if ptr is not NULL, it must have been returned by an earlier call to mm malloc or mm realloc. + * + * The call to mm realloc changes the size of the memory block pointed to by ptr (the old block) + * to size bytes and returns the address of the new block. Notice that the address of the + * new block might be the same as the old block, or it might be different, depending on your + * implementation, the amount of internal fragmentation in the old block, and the size of the + * realloc request. The contents of the new block are the same as those of the old ptr block, up + * to the minimum of the old and new sizes. Everything else is uninitialized. + * + * For example, if the old block is 8 bytes and the new block is 12 bytes, then the first 8 bytes + * of the new block are identical to the first 8 bytes of the old block and the last 4 bytes are + * uninitialized. + * + * Similarly, if the old block is 8 bytes and the new block is 4 bytes, then the + * contents of the new block are identical to the first 4 bytes of the old block. + */ + + if(ptr == NULL && size > 0){ + return mm_malloc(size); + } else if(ptr != NULL && size == 0) { + mm_free(ptr); + return NULL; + } else if(ptr != NULL && size > 0) { + size_t oldSize = GET_SIZE(HDRP(ptr)); + + /* Adjust block size to include overhead and alignment reqs. */ + if (size <= WSIZE) { + size = WSIZE + OVERHEAD; + } + else { + size = DSIZE * ((size + OVERHEAD + DSIZE - 1) / DSIZE); + } + + // if sizes are the same or the difference is less than a DSIZE, no changes needed + if(oldSize == size || (oldSize - size <= WSIZE)) { + return ptr; + } else { + + // If size is less than old size, shrink and free end + if(size < oldSize) { + if ((oldSize - size) >= DSIZE) { + PUT(HDRP(ptr), PACK(size, 0)); + PUT(HDRP(NEXT_BLKP(ptr)), PACK(oldSize-size, 1)); + mm_coalesce(NEXT_BLKP(ptr)); + } + else { + PUT(HDRP(ptr), PACK(oldSize, 0)); + } + return ptr; + } + + // If size is greater than old size, grow and free end + else if(size > oldSize) { + size_t nextSize = GET_SIZE(HDRP(NEXT_BLKP(ptr))) + oldSize; + if(GET_ALLOC(HDRP(NEXT_BLKP(ptr))) && nextSize >= size){ + if ((nextSize - size) >= DSIZE) { + PUT(HDRP(ptr), PACK(size, 0)); + PUT(HDRP(NEXT_BLKP(ptr)), PACK(nextSize-size, 1)); + mm_coalesce(NEXT_BLKP(ptr)); + } + else { + PUT(HDRP(ptr), PACK(nextSize, 0)); + } + + return ptr; + } + // else malloc + void * newPtr; + if((newPtr = mm_malloc(size)) == NULL){ + return NULL; + } + // copy memory + mm_memcpy(newPtr, ptr); + // free + mm_free(ptr); + return newPtr; + } + + } + } + return NULL; } +/** + * mm_memcpy - copies memory to destination from source + * + * Memory is coppied block by block and truncated if + * destination is smaller than source + */ + +void mm_memcpy(void * dest, void * src) +{ + for(size_t i = 0; i < GET_SIZE(HDRP(dest))-OVERHEAD; i++){ + ((char *) dest)[i] = ((char *) src)[i]; + } +} + /* * mm_checkheap - Check the heap for consistency */