forked from xuos/xiuos
				
			
		
			
				
	
	
		
			370 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			370 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
/*
 | 
						|
 * mm.c - malloc using segregated list
 | 
						|
 * KAIST
 | 
						|
 * Tony Kim
 | 
						|
 *
 | 
						|
 * In this approach,
 | 
						|
 * Every block has a header and a footer
 | 
						|
 * in which header contains reallocation information, size, and allocation info
 | 
						|
 * and footer contains size and allocation info.
 | 
						|
 * Free list are tagged to the segregated list.
 | 
						|
 * Therefore all free block contains pointer to the predecessor and successor.
 | 
						|
 * The segregated list headers are organized by 2^k size.
 | 
						|
 *
 | 
						|
 */
 | 
						|
 | 
						|
#include "libmem.h"
 | 
						|
#include "usyscall.h"
 | 
						|
 | 
						|
/* 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)
 | 
						|
 | 
						|
// My additional Macros
 | 
						|
#define WSIZE 4 // word and header/footer size (bytes)
 | 
						|
#define DSIZE 8 // double word size (bytes)
 | 
						|
#define INITCHUNKSIZE (1 << 6)
 | 
						|
#define CHUNKSIZE (1 << 12) //+(1<<7)
 | 
						|
 | 
						|
#define LISTLIMIT 20
 | 
						|
 | 
						|
#define MAX(x, y) ((x) > (y) ? (x) : (y))
 | 
						|
#define MIN(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) (*(unsigned int*)(p))
 | 
						|
#define PUT(p, val) (*(unsigned int*)(p) = (val) | GET_TAG(p))
 | 
						|
#define PUT_NOTAG(p, val) (*(unsigned int*)(p) = (val))
 | 
						|
 | 
						|
// Store predecessor or successor pointer for free blocks
 | 
						|
#define SET_PTR(p, ptr) (*(unsigned int*)(p) = (unsigned int)(ptr))
 | 
						|
 | 
						|
// Read the size and allocation bit from address p
 | 
						|
#define GET_SIZE(p) (GET(p) & ~0x7)
 | 
						|
#define GET_ALLOC(p) (GET(p) & 0x1)
 | 
						|
#define GET_TAG(p) (GET(p) & 0x2)
 | 
						|
#define SET_RATAG(p) (GET(p) |= 0x2)
 | 
						|
#define REMOVE_RATAG(p) (GET(p) &= ~0x2)
 | 
						|
 | 
						|
// Address of block's header and footer
 | 
						|
#define HDRP(ptr) ((char*)(ptr)-WSIZE)
 | 
						|
#define FTRP(ptr) ((char*)(ptr) + GET_SIZE(HDRP(ptr)) - DSIZE)
 | 
						|
 | 
						|
// Address of (physically) 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))
 | 
						|
 | 
						|
// Address of free block's predecessor and successor entries
 | 
						|
#define PRED_PTR(ptr) ((char*)(ptr))
 | 
						|
#define SUCC_PTR(ptr) ((char*)(ptr) + WSIZE)
 | 
						|
 | 
						|
// Address of free block's predecessor and successor on the segregated list
 | 
						|
#define PRED(ptr) (*(char**)(ptr))
 | 
						|
#define SUCC(ptr) (*(char**)(SUCC_PTR(ptr)))
 | 
						|
 | 
						|
// End of my additional macros
 | 
						|
 | 
						|
// Global var
 | 
						|
void* segregated_free_lists[LISTLIMIT];
 | 
						|
 | 
						|
// Functions
 | 
						|
static void* extend_heap(size_t size);
 | 
						|
static void* coalesce(void* ptr);
 | 
						|
static void* place(void* ptr, size_t asize);
 | 
						|
static void insert_node(void* ptr, size_t size);
 | 
						|
static void delete_node(void* ptr);
 | 
						|
 | 
						|
static uintptr_t userland_heap_base;
 | 
						|
static uintptr_t userland_heap_top;
 | 
						|
static uintptr_t requested_heap_size;
 | 
						|
 | 
						|
static void* mem_sbrk(size_t size)
 | 
						|
{
 | 
						|
    uintptr_t userland_heap_size = userland_heap_top - userland_heap_base;
 | 
						|
    if (userland_heap_size - requested_heap_size >= size) {
 | 
						|
        void* ret_ptr = (void*)(userland_heap_base + requested_heap_size);
 | 
						|
        requested_heap_size += size;
 | 
						|
        return ret_ptr;
 | 
						|
    }
 | 
						|
 | 
						|
    uintptr_t size_needed = size - (userland_heap_size - requested_heap_size);
 | 
						|
    userland_heap_top = mmap(userland_heap_top, (uintptr_t)NULL, size_needed, false);
 | 
						|
 | 
						|
    return mem_sbrk(size);
 | 
						|
}
 | 
						|
 | 
						|
static void* extend_heap(size_t size)
 | 
						|
{
 | 
						|
    void* ptr;
 | 
						|
    size_t asize; // Adjusted size
 | 
						|
 | 
						|
    asize = ALIGN(size);
 | 
						|
 | 
						|
    if ((ptr = mem_sbrk(asize)) == (void*)-1)
 | 
						|
        return NULL;
 | 
						|
 | 
						|
    // Set headers and footer
 | 
						|
    PUT_NOTAG(HDRP(ptr), PACK(asize, 0));
 | 
						|
    PUT_NOTAG(FTRP(ptr), PACK(asize, 0));
 | 
						|
    PUT_NOTAG(HDRP(NEXT_BLKP(ptr)), PACK(0, 1));
 | 
						|
    insert_node(ptr, asize);
 | 
						|
 | 
						|
    return coalesce(ptr);
 | 
						|
}
 | 
						|
 | 
						|
static void insert_node(void* ptr, size_t size)
 | 
						|
{
 | 
						|
    int list = 0;
 | 
						|
    void* search_ptr = ptr;
 | 
						|
    void* insert_ptr = NULL;
 | 
						|
 | 
						|
    // Select segregated list
 | 
						|
    while ((list < LISTLIMIT - 1) && (size > 1)) {
 | 
						|
        size >>= 1;
 | 
						|
        list++;
 | 
						|
    }
 | 
						|
 | 
						|
    // Keep size ascending order and search
 | 
						|
    search_ptr = segregated_free_lists[list];
 | 
						|
    while ((search_ptr != NULL) && (size > GET_SIZE(HDRP(search_ptr)))) {
 | 
						|
        insert_ptr = search_ptr;
 | 
						|
        search_ptr = PRED(search_ptr);
 | 
						|
    }
 | 
						|
 | 
						|
    // Set predecessor and successor
 | 
						|
    if (search_ptr != NULL) {
 | 
						|
        if (insert_ptr != NULL) {
 | 
						|
            SET_PTR(PRED_PTR(ptr), search_ptr);
 | 
						|
            SET_PTR(SUCC_PTR(search_ptr), ptr);
 | 
						|
            SET_PTR(SUCC_PTR(ptr), insert_ptr);
 | 
						|
            SET_PTR(PRED_PTR(insert_ptr), ptr);
 | 
						|
        } else {
 | 
						|
            SET_PTR(PRED_PTR(ptr), search_ptr);
 | 
						|
            SET_PTR(SUCC_PTR(search_ptr), ptr);
 | 
						|
            SET_PTR(SUCC_PTR(ptr), NULL);
 | 
						|
            segregated_free_lists[list] = ptr;
 | 
						|
        }
 | 
						|
    } else {
 | 
						|
        if (insert_ptr != NULL) {
 | 
						|
            SET_PTR(PRED_PTR(ptr), NULL);
 | 
						|
            SET_PTR(SUCC_PTR(ptr), insert_ptr);
 | 
						|
            SET_PTR(PRED_PTR(insert_ptr), ptr);
 | 
						|
        } else {
 | 
						|
            SET_PTR(PRED_PTR(ptr), NULL);
 | 
						|
            SET_PTR(SUCC_PTR(ptr), NULL);
 | 
						|
            segregated_free_lists[list] = ptr;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
static void delete_node(void* ptr)
 | 
						|
{
 | 
						|
    int list = 0;
 | 
						|
    size_t size = GET_SIZE(HDRP(ptr));
 | 
						|
 | 
						|
    // Select segregated list
 | 
						|
    while ((list < LISTLIMIT - 1) && (size > 1)) {
 | 
						|
        size >>= 1;
 | 
						|
        list++;
 | 
						|
    }
 | 
						|
 | 
						|
    if (PRED(ptr) != NULL) {
 | 
						|
        if (SUCC(ptr) != NULL) {
 | 
						|
            SET_PTR(SUCC_PTR(PRED(ptr)), SUCC(ptr));
 | 
						|
            SET_PTR(PRED_PTR(SUCC(ptr)), PRED(ptr));
 | 
						|
        } else {
 | 
						|
            SET_PTR(SUCC_PTR(PRED(ptr)), NULL);
 | 
						|
            segregated_free_lists[list] = PRED(ptr);
 | 
						|
        }
 | 
						|
    } else {
 | 
						|
        if (SUCC(ptr) != NULL) {
 | 
						|
            SET_PTR(PRED_PTR(SUCC(ptr)), NULL);
 | 
						|
        } else {
 | 
						|
            segregated_free_lists[list] = NULL;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
static void* coalesce(void* ptr)
 | 
						|
{
 | 
						|
    size_t prev_alloc = GET_ALLOC(HDRP(PREV_BLKP(ptr)));
 | 
						|
    size_t next_alloc = GET_ALLOC(HDRP(NEXT_BLKP(ptr)));
 | 
						|
    size_t size = GET_SIZE(HDRP(ptr));
 | 
						|
 | 
						|
    // Do not coalesce with previous block if the previous block is tagged with Reallocation tag
 | 
						|
    if (GET_TAG(HDRP(PREV_BLKP(ptr))))
 | 
						|
        prev_alloc = 1;
 | 
						|
 | 
						|
    if (prev_alloc && next_alloc) { // Case 1
 | 
						|
        return ptr;
 | 
						|
    } else if (prev_alloc && !next_alloc) { // Case 2
 | 
						|
        delete_node(ptr);
 | 
						|
        delete_node(NEXT_BLKP(ptr));
 | 
						|
        size += GET_SIZE(HDRP(NEXT_BLKP(ptr)));
 | 
						|
        PUT(HDRP(ptr), PACK(size, 0));
 | 
						|
        PUT(FTRP(ptr), PACK(size, 0));
 | 
						|
    } else if (!prev_alloc && next_alloc) { // Case 3
 | 
						|
        delete_node(ptr);
 | 
						|
        delete_node(PREV_BLKP(ptr));
 | 
						|
        size += GET_SIZE(HDRP(PREV_BLKP(ptr)));
 | 
						|
        PUT(FTRP(ptr), PACK(size, 0));
 | 
						|
        PUT(HDRP(PREV_BLKP(ptr)), PACK(size, 0));
 | 
						|
        ptr = PREV_BLKP(ptr);
 | 
						|
    } else { // Case 4
 | 
						|
        delete_node(ptr);
 | 
						|
        delete_node(PREV_BLKP(ptr));
 | 
						|
        delete_node(NEXT_BLKP(ptr));
 | 
						|
        size += GET_SIZE(HDRP(PREV_BLKP(ptr))) + GET_SIZE(HDRP(NEXT_BLKP(ptr)));
 | 
						|
        PUT(HDRP(PREV_BLKP(ptr)), PACK(size, 0));
 | 
						|
        PUT(FTRP(NEXT_BLKP(ptr)), PACK(size, 0));
 | 
						|
        ptr = PREV_BLKP(ptr);
 | 
						|
    }
 | 
						|
 | 
						|
    insert_node(ptr, size);
 | 
						|
 | 
						|
    return ptr;
 | 
						|
}
 | 
						|
 | 
						|
static void* place(void* ptr, size_t asize)
 | 
						|
{
 | 
						|
    size_t ptr_size = GET_SIZE(HDRP(ptr));
 | 
						|
    size_t remainder = ptr_size - asize;
 | 
						|
 | 
						|
    delete_node(ptr);
 | 
						|
 | 
						|
    if (remainder <= DSIZE * 2) {
 | 
						|
        // Do not split block
 | 
						|
        PUT(HDRP(ptr), PACK(ptr_size, 1));
 | 
						|
        PUT(FTRP(ptr), PACK(ptr_size, 1));
 | 
						|
    }
 | 
						|
 | 
						|
    else if (asize >= 100) {
 | 
						|
        // Split block
 | 
						|
        PUT(HDRP(ptr), PACK(remainder, 0));
 | 
						|
        PUT(FTRP(ptr), PACK(remainder, 0));
 | 
						|
        PUT_NOTAG(HDRP(NEXT_BLKP(ptr)), PACK(asize, 1));
 | 
						|
        PUT_NOTAG(FTRP(NEXT_BLKP(ptr)), PACK(asize, 1));
 | 
						|
        insert_node(ptr, remainder);
 | 
						|
        return NEXT_BLKP(ptr);
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
    else {
 | 
						|
        // Split block
 | 
						|
        PUT(HDRP(ptr), PACK(asize, 1));
 | 
						|
        PUT(FTRP(ptr), PACK(asize, 1));
 | 
						|
        PUT_NOTAG(HDRP(NEXT_BLKP(ptr)), PACK(remainder, 0));
 | 
						|
        PUT_NOTAG(FTRP(NEXT_BLKP(ptr)), PACK(remainder, 0));
 | 
						|
        insert_node(NEXT_BLKP(ptr), remainder);
 | 
						|
    }
 | 
						|
    return ptr;
 | 
						|
}
 | 
						|
 | 
						|
static bool malloc_inited = false;
 | 
						|
int mm_init(void)
 | 
						|
{
 | 
						|
    // init heap
 | 
						|
    userland_heap_base = task_heap_base();
 | 
						|
    userland_heap_top = userland_heap_base;
 | 
						|
    requested_heap_size = 0;
 | 
						|
 | 
						|
    int list;
 | 
						|
    char* heap_start; // Pointer to beginning of heap
 | 
						|
 | 
						|
    // Initialize segregated free lists
 | 
						|
    for (list = 0; list < LISTLIMIT; list++) {
 | 
						|
        segregated_free_lists[list] = NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    // Allocate memory for the initial empty heap
 | 
						|
    if ((long)(heap_start = mem_sbrk(4 * WSIZE)) == -1)
 | 
						|
        return -1;
 | 
						|
 | 
						|
    PUT_NOTAG(heap_start, 0); /* Alignment padding */
 | 
						|
    PUT_NOTAG(heap_start + (1 * WSIZE), PACK(DSIZE, 1)); /* Prologue header */
 | 
						|
    PUT_NOTAG(heap_start + (2 * WSIZE), PACK(DSIZE, 1)); /* Prologue footer */
 | 
						|
    PUT_NOTAG(heap_start + (3 * WSIZE), PACK(0, 1)); /* Epilogue header */
 | 
						|
 | 
						|
    if (extend_heap(INITCHUNKSIZE) == NULL)
 | 
						|
        return -1;
 | 
						|
 | 
						|
    malloc_inited = true;
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
void* malloc(size_t size)
 | 
						|
{
 | 
						|
    while (!malloc_inited) {
 | 
						|
        mm_init();
 | 
						|
    }
 | 
						|
 | 
						|
    size_t asize; /* Adjusted block size */
 | 
						|
    size_t extendsize; /* Amount to extend heap if no fit */
 | 
						|
    void* ptr = NULL; /* Pointer */
 | 
						|
 | 
						|
    // Ignore size 0 cases
 | 
						|
    if (size == 0)
 | 
						|
        return NULL;
 | 
						|
 | 
						|
    // Align block size
 | 
						|
    if (size <= DSIZE) {
 | 
						|
        asize = 2 * DSIZE;
 | 
						|
    } else {
 | 
						|
        asize = ALIGN(size + DSIZE);
 | 
						|
    }
 | 
						|
 | 
						|
    int list = 0;
 | 
						|
    size_t searchsize = asize;
 | 
						|
    // Search for free block in segregated list
 | 
						|
    while (list < LISTLIMIT) {
 | 
						|
        if ((list == LISTLIMIT - 1) || ((searchsize <= 1) && (segregated_free_lists[list] != NULL))) {
 | 
						|
            ptr = segregated_free_lists[list];
 | 
						|
            // Ignore blocks that are too small or marked with the reallocation bit
 | 
						|
            while ((ptr != NULL) && ((asize > GET_SIZE(HDRP(ptr))) || (GET_TAG(HDRP(ptr))))) {
 | 
						|
                ptr = PRED(ptr);
 | 
						|
            }
 | 
						|
            if (ptr != NULL)
 | 
						|
                break;
 | 
						|
        }
 | 
						|
 | 
						|
        searchsize >>= 1;
 | 
						|
        list++;
 | 
						|
    }
 | 
						|
 | 
						|
    // if free block is not found, extend the heap
 | 
						|
    if (ptr == NULL) {
 | 
						|
        extendsize = MAX(asize, CHUNKSIZE);
 | 
						|
 | 
						|
        if ((ptr = extend_heap(extendsize)) == NULL)
 | 
						|
            return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    // Place and divide block
 | 
						|
    ptr = place(ptr, asize);
 | 
						|
 | 
						|
    // Return pointer to newly allocated block
 | 
						|
    return ptr;
 | 
						|
}
 | 
						|
 | 
						|
void free(void* ptr)
 | 
						|
{
 | 
						|
    size_t size = GET_SIZE(HDRP(ptr));
 | 
						|
 | 
						|
    REMOVE_RATAG(HDRP(NEXT_BLKP(ptr)));
 | 
						|
    PUT(HDRP(ptr), PACK(size, 0));
 | 
						|
    PUT(FTRP(ptr), PACK(size, 0));
 | 
						|
 | 
						|
    insert_node(ptr, size);
 | 
						|
    coalesce(ptr);
 | 
						|
 | 
						|
    return;
 | 
						|
}
 |