You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

333 lines
10 KiB

/*
* mm-naive.c - The fastest, least memory-efficient malloc package.
*
* In this naive approach, a block is allocated by simply incrementing
* the brk pointer. A block is pure payload. There are no headers or
* footers. Blocks are never coalesced or reused. Realloc is
* implemented directly using mm_malloc and mm_free.
*
* NOTE TO STUDENTS: Replace this header comment with your own header
* comment that gives a high level description of your solution.
*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <string.h>
#include "mm.h"
#include "memlib.h"
/*********************************************************
* NOTE TO STUDENTS: Before you do anything else, please
* provide your team information in the following struct.
********************************************************/
team_t team = {
/* Team name */
"ateam",
/* First member's full name */
"Harry Bovik",
/* First member's email address */
"bovik@cs.cmu.edu",
/* Second member's full name (leave blank if none) */
"",
/* Second member's email address (leave blank if none) */
""
};
/* single word (4) or double word (8) alignment */
#define ALIGNMENT 8
/* rounds up to the nearest multiple of ALIGNMENT */
#define ALIGN(size) (((size) + (ALIGNMENT-1)) & ~0x7)
#define SIZE_T_SIZE (ALIGN(sizeof(size_t)))
#define WSIZE 4 /* Word and header/footer size (bytes) */
#define DSIZE 8 /* Double word size (bytes) */
#define CHUNKSIZE (1<<12) /* Extend heap by this amount (bytes) */
#define MAX(x, y) ((x) > (y)? (x) : (y))
#define MIN(x, y) ((x) > (y)? (y) : (x))
/* Pack a size and allocated bit into a word(4 bytes) */
#define PACK(size, alloc) ((size) | (alloc))
/* Read and write a word at address p */
#define GET(ptr) (*(unsigned int *)(ptr))
#define PUT(ptr, val) (*(unsigned int *)(ptr) = (val))
/* not affected in the case that the first bit is 1 */
/* if use int, may affected */
/* Read the size and allocated flags from address ptr */
#define GET_SIZE(ptr) (GET(ptr) & ~0x7)
#define GET_ALLOC(ptr) (GET(ptr) & 0x1)
/* ALIGN return the nearest multiple of 8, so the last 3 bits are always 000 */
/* Given block ptr ptr, compute address of its header and footer */
#define HDRP(ptr) ((char *)(ptr) - WSIZE)
#define FTRP(ptr) ((char *)(ptr) + GET_SIZE(HDRP(ptr)) - DSIZE)
/* Given block ptr ptr, compute address of next and previous blocks */
#define NEXT_BLKP(ptr) ((char *)(ptr) + GET_SIZE(((char *)(ptr) - WSIZE)))
#define PREV_BLKP(ptr) ((char *)(ptr) - GET_SIZE(((char *)(ptr) - DSIZE)))
/* ptr means the address of payload */
/*
* I don't know why PREV_BLKP is written like this, but according to the information
* I have found, it seems that this method can work properly.
*/
/* Modified micros */
/* Add two micros only for free blocks */
/* Point to next and prev free block, only free blocks have*/
#define PREV_LINKNODE_RP(ptr) ((char *)(ptr))
#define NEXT_LINKNODE_RP(ptr) ((char *)(ptr) + WSIZE)
char *heap_ptr = NULL;
char *root = NULL;
/*
* Insert_linknode - insert p to the root of explcit list.
*/
inline void insert_linknode(char *p){ //inline decreases the cost of calling the func.
/* insert p to explcit list. */
char *next = GET(root);
if (next != NULL)
PUT(PREV_LINKNODE_RP(next), p);
PUT(NEXT_LINKNODE_RP(p), next);
PUT(root, p);
}
/*
* Del_linknode - delete linknode p.
*/
inline void del_linknode(char *p){
char *prev = GET(PREV_LINKNODE_RP(p));
char *next = GET(NEXT_LINKNODE_RP(p));
if (prev == NULL){
if (next != NULL)
PUT(PREV_LINKNODE_RP(next), 0);
PUT(root, next);
}
else if (prev != NULL){
if (next != NULL)
PUT(PREV_LINKNODE_RP(next), prev);
PUT(NEXT_LINKNODE_RP(prev), next);
}
PUT(NEXT_LINKNODE_RP(p), 0);
PUT(PREV_LINKNODE_RP(p), 0);
}
/*
* coalesce - Boundary tag coalescing. Return ptr to coalesced block
*/
static void *coalesce(void *ptr)
{
size_t prev_alloc = GET_ALLOC(FTRP(PREV_BLKP(ptr)));
size_t next_alloc = GET_ALLOC(HDRP(NEXT_BLKP(ptr)));
size_t size = GET_SIZE(HDRP(ptr));
if (prev_alloc && next_alloc) { /* left and right used */
//return ptr;
}
else if (prev_alloc && !next_alloc) { /* only right free */
size += GET_SIZE(HDRP(NEXT_BLKP(ptr)));
del_linknode(NEXT_LINKNODE_RP(ptr)); /* remove from linklist*/
PUT(HDRP(ptr), PACK(size, 0));
PUT(FTRP(ptr), PACK(size,0));
}
else if (!prev_alloc && next_alloc) { /* only left free */
size += GET_SIZE(HDRP(PREV_BLKP(ptr)));
del_linknode(PREV_BLKP(ptr));
PUT(FTRP(ptr), PACK(size, 0));
PUT(HDRP(PREV_BLKP(ptr)), PACK(size, 0));
ptr = PREV_BLKP(ptr);
}
else { /* both sides free */
size += GET_SIZE(HDRP(PREV_BLKP(ptr))) +
GET_SIZE(FTRP(NEXT_BLKP(ptr)));
del_linknode(PREV_BLKP(ptr));
del_linknode(NEXT_BLKP(ptr));
PUT(HDRP(PREV_BLKP(ptr)), PACK(size, 0));
PUT(FTRP(NEXT_BLKP(ptr)), PACK(size, 0));
ptr = PREV_BLKP(ptr);
}
insert_linknode(ptr);
return ptr;
}
/*
* extend_heap - Extend heap with free block and return its block pointer
*/
static void *extend_heap(size_t extendsize)
{
char *ptr;
size_t size;
/* Allocate an even number of extendsize to maintain alignment */
size = (extendsize % 2) ? (extendsize+1) * WSIZE : extendsize * WSIZE;
if ((long)(ptr = mem_sbrk(size)) == -1) /* this means ptr -> 0xffffffff */
return NULL;
/* Initialize free block header,footer and the epilogue header */
PUT(HDRP(ptr), PACK(size, 0)); /* Free block header */
PUT(FTRP(ptr), PACK(size, 0)); /* Free block footer */
// HDRP make a left 8-bits shift, the same to a node size.
PUT(NEXT_LINKNODE_RP(ptr), 0); /* Next linknode */
PUT(PREV_LINKNODE_RP(ptr), 0); /* Prev linknode */
PUT(HDRP(NEXT_BLKP(ptr)), PACK(0, 1)); /* New epilogue header */
/* Coalesce free blocks */
return coalesce(ptr);
}
/*
* find_fit - Find a fit for a block with size bytes
*/
static void *find_fit(size_t asize)
{
char *tmp = GET(root);
int count = 0;
while (tmp != NULL){
if (GET_SIZE(HDRP(tmp)) >= asize && (count++) != 0)
return tmp;
tmp = GET(NEXT_LINKNODE_RP(tmp));
}
return NULL; /* No fit */
}
/*
* place - Place block of size bytes at start of free block ptr
* and split if remainder would be at least minimum block size
*/
static void place(void *ptr, size_t size)
{
size_t newsize = GET_SIZE(HDRP(ptr));
del_linknode(ptr);
if ((newsize - size) >= (2*DSIZE)) {
PUT(HDRP(ptr), PACK(size, 1));
PUT(FTRP(ptr), PACK(size, 1));
ptr = NEXT_BLKP(ptr);
PUT(HDRP(ptr), PACK(newsize-size, 0));
PUT(FTRP(ptr), PACK(newsize-size, 0));
PUT(NEXT_LINKNODE_RP(ptr), 0);
PUT(PREV_LINKNODE_RP(ptr), 0);
coalesce(ptr);
}
else {
PUT(HDRP(ptr), PACK(newsize, 1));
PUT(FTRP(ptr), PACK(newsize, 1));
}
}
int mm_init(void)
{
/* Create the initial empty heap */
if ((heap_ptr = mem_sbrk(6*WSIZE)) == (void *)-1) /* 0xffffffff */
return -1;
PUT(heap_ptr, 0); /* Alignment padding */
PUT(heap_ptr + (1*WSIZE), 0); /* Free prev linknode */
PUT(heap_ptr + (2*WSIZE), 0); /* Free next linknode */
PUT(heap_ptr + (3*WSIZE), PACK(DSIZE, 1)); /* Prologue header */
PUT(heap_ptr + (4*WSIZE), PACK(DSIZE, 1)); /* Prologue footer */
PUT(heap_ptr + (5*WSIZE), PACK(0, 1)); /* Epilogue header */
root = heap_ptr + (1 * WSIZE);
heap_ptr += (4*WSIZE);
/* Extend the empty heap with a free block of CHUNKSIZE bytes */
if (extend_heap(CHUNKSIZE/WSIZE) == NULL)
return -1;
return 0;
}
void *mm_malloc(size_t size)
{
size_t newsize; /* Adjusted block size */
size_t extendsize; /* Amount to extend heap if no fit */
char *ptr;
if (heap_ptr == NULL){
mm_init();
}
if (size == 0)
return NULL;
/* Adjust block size to include overhead and alignment reqs. */
/* Need to use this method, but I don't know why */
if (size <= DSIZE)
newsize = 2*DSIZE;
else
newsize = DSIZE * ((size + (DSIZE) + (DSIZE-1)) / DSIZE);
/* Search the free list for a fit */
if ((ptr = find_fit(newsize)) != NULL) {
place(ptr, newsize);
return ptr;
}
/* No fit found. Get more memory and place the block */
extendsize = MAX(newsize,CHUNKSIZE);
if ((ptr = extend_heap(extendsize/WSIZE)) == NULL)
return NULL;
place(ptr, newsize);
return ptr;
}
void mm_free(void *ptr)
{
if (ptr == NULL)
return;
size_t size = GET_SIZE(HDRP(ptr));
PUT(HDRP(ptr), PACK(size, 0));
PUT(FTRP(ptr), PACK(size, 0));
/* Reset linknodes */
PUT(NEXT_LINKNODE_RP(ptr), 0);
PUT(PREV_LINKNODE_RP(ptr), 0);
coalesce(ptr);
}
void *mm_realloc(void *ptr, size_t size)
{
size_t oldsize;
void *newptr;
if(size == 0) {
mm_free(ptr);
return 0;
}
if(ptr == NULL) {
return mm_malloc(size);
}
newptr = mm_malloc(size);
/* realloc failed */
if(newptr == NULL) {
return 0;
}
/* Copy the old heap area. */
oldsize = GET_SIZE(HDRP(ptr));
if(size < oldsize)
oldsize = size;
memcpy(newptr, ptr, oldsize);
/* Free the old block. */
mm_free(ptr);
return newptr;
}