CMU15-213 ICS lab-malloc

/*
 * mm-explicit link list.c - The fastest, highest memory-efficient malloc package I think of.
 * 
 * In this  approach, a block is allocated by simply incrementing
 * the brk pointer. 
 * 空闲块组织成双向链表,并按块的大小升序排列,首块的prev指向尾块,但尾块的next为NULL作为空闲链表的边界
 * malloc分配策略使用First Fit策略,保证最大内存利用率,而新分配一个块的时间需要o(k),k:空闲块的数量,
 * 而释放能够在常数时间内完成
 * Realloc is implemented directly using mm_malloc and mm_free.
 * 
 *                 31   30  29  28  .......                                    3       2       1      0   
 *               +-----4B-------|------4B----------|--------4B--------|---------------------------------+
 *               |           |                |                |                   | unused | 1/0 | 1/0 |                  |
 *               +--------------------------------------------------------------------------------------+
 *                                                                                             |     |
 *                                                          表示前面一个块是否为allocated(1)<==+     |
 *                                                               表示此块是否为allocated  <===========+
 *
 *
 *
 *
 *  1)空闲块 
 *               +-----4B-----|----4B-----|----4B----|---size meet alignment  requs----------|---4B-----+
 *               |    header  |   prev    |   next   |        payload                        |  footer  |
 *               +--------------------------------------------------------------------------------------+
 *空闲块有两种状态:a)在explicit link list;    b)Suspended (Read to operate such as  Delete. )
 *
 *  2)分配块
 *              +-----4B--------|-----------------------------------------------------------------------+
 *              |     header    |                          payload                                      |       
 *              +---------------------------------------------------------------------------------------+
 * 
 * origin head
 *              +--------|--------|--------|--------------------------------------------|---------|
 *              |   0    | 8/(1,1)  8/(1,1)| header|  prev  | next   |  payload | footer|0/(1,0/1)|
 *              +--------|--------|--------|--------------------------------------------|---------|
 *                              prologue       first block                               epilogue
 *
 *  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 */
    "Shakspear",
        /* First member's full name */
    "June Eleventh",
        /* First member's email address */
    "1569496189@qq.com",
    /* Second member's full name (leave blank if none) */
    "",
    /* Second member's email address (leave blank if none) */
    ""
};

/* Varibals    之前用(void *)而非(char*) */
static char *heap_listp;
static char *first_freeblock;

/* 宏 */
//#define DEBUG

// 想要打印出来的地方加上这个:
/*
 *
#ifdef DEBUG
    mm_check(__FUNCTION__);
#endif // DEBUG
 * 
 */


/* 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 by myself*/
#define WSIZE 4
#define DSIZE 8
//#define LEN_PTR sizeof(void *)
#define CHUNKSIZE (1<<12)   //4K
//#define MINIBLK_SIZE   (DSIZE+2*LEN_PTR)
#define MINIBLK_SIZE   16
#define MAX(x, y) (x>y?x;y)

/* pack a size allocated bit and the previous block allocated bit into a word */
#define PACK(size, alloc, prev_alloc)    ((size) | alloc | (prev_alloc << 1))

/* GET获取数据,PUT写入数据 */
#define GET(p) (*(unsigned int *)(p))
#define PUT(p, val)  (*(unsigned int *)(p) = val) 

/* read the size and allocated fileds from address p */
#define GET_SIZE(p) (GET(p) & ~0x7)
#define GET_ALLOC(p)    (GET(p) & 0x1)
#define GET_PREVALLOC(p)    ((GET(p) & 0x2) >> 1)

/* Given the 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 the block ptr bp, compute address of its previous and next blocks in adjacent address */
#define NEXT_BLKP(bp)   ((char *)bp + GET_SIZE(HDRP(bp)))
#define PREV_BLKP(bp)   ((char *)bp - GET_SIZE(HDRP(bp) - WSIZE))   /* Only the previous block is free */

/* 通过链表链接的空闲块 */ 
/*  Given the block ptr bp, compute fields address of its previous ptr and next ptr  */
/*  指向bp的prev域和next域 Very important   */
/* 何不用64位长的long int 来记录地址呢? interesting! I found out the length of the block address will not exceed 32 bits */
// #define LINKPREV_BLKP(bp)   (*(char **)bp)           //分辨不出内存里是指针还是数值
// #define LINKNEXT_BLKP(bp)  (*((char **)(bp) + LEN_PTR))
#define LINKPREV_BLKP(bp)   ((char *)bp)             //指向该块的next域和prev域
#define LINKNEXT_BLKP(bp)  ((char *)(bp) + WSIZE)


/*              函数原型             */
static void place(void *bp, size_t asize);
static void *Whole_Coalesce(size_t size);
static  void *find_fit(size_t asize);
static void *Coalesce(void *bp);
static void *Delete( void *bp);
static void Insert(void *insert_startp, void* bp );
static void *extend_heap(size_t words);
static void SET_NEXTBLKP_PREVALLOC(char *bp, size_t val);
int mm_check(char *func);




 /* 若返回0 代表检查出错 */
int mm_check(char *func){
    char *ep=first_freeblock;
    char *start=(void *)mem_heap_lo(), *end=(void *)mem_heap_hi();
    printf("\t堆的范围是:[ 0x%x  ======>  0x%x] \n", start, end);
    /* 检查list是否为空 */
    /*
    if(first_freeblock == NULL)
        printf("free list state: Empty Empty Empty!\n");
    else
        printf("free list state: existed existed existed!\n");
    */
    
    /* 1.查看free list 中的块的prev和next域是否都在堆中 */
    for(ep=first_freeblock; ep!=NULL; ep=(char *)GET(LINKNEXT_BLKP(ep))){
        /* 若标记位为1,代表出错 */
        if( (long)GET(LINKPREV_BLKP(ep)) < (long)start || (long)GET(LINKPREV_BLKP(ep)) > (long)end) {
            printf("*** *** 空闲链表中的块的prev域出错, 不在堆范围内!\n");
             printf("该块的地址为:0x%x\n",ep);
            return 0;
        }
        if( (char *)GET(LINKNEXT_BLKP(ep)) != NULL 
            &&((long)GET(LINKNEXT_BLKP(ep))<(long)start || (long)GET(LINKNEXT_BLKP(ep))> (long)end)){                                         
            printf("*** *** 空闲链表中的块的next域出错, 不在堆范围内!\n");
             printf("该块的地址为:0x%x\n",ep);
             return 0;
        }
        if( (char *)GET(LINKNEXT_BLKP(ep)) == ep) {
            printf("*** *** 空闲链表中的块的next域出错, 指向了自己!\t");
             printf("该块的地址为:0x%x\n",ep);
            return 0;
        }
    }
    /* 2.查看堆中所有块块的PREV_ALLOC位是否和前面的块的分配位一致 */
    for(ep=first_freeblock; (long)ep < (long)((long)end -3); ep=(char *)NEXT_BLKP(ep) ){
        /* 若标记位为1,代表出错 */
        if( GET_ALLOC(HDRP(ep)) != GET_PREVALLOC(HDRP(NEXT_BLKP(ep))) ) {
            printf("*** *** 空闲链表中的块 ALLOC标记与后一块的PREV_ALLOC位矛盾!\n");
             printf("该块的地址为:0x%x, ALLOC:%d\n",ep, GET_ALLOC(HDRP(ep)) );
             printf("后块的地址为:0x%x, PREV_ALLOC:%d \n\n",NEXT_BLKP(ep), GET_PREVALLOC(HDRP(NEXT_BLKP(ep))) );
            return 0;
        }
    }
    /*  3.检查空闲链表中的块是否都是被标记成0(free) */
    for(ep=first_freeblock; ep!=NULL; ep=(char *)GET(LINKNEXT_BLKP(ep))){
        /* 若标记位为1,代表出错 */
        if( GET_ALLOC(HDRP(ep))  ) {
            printf("*** *** 空闲链表中的块 ALLOC标记位出错, 应该为0!\n");
             printf("该块的地址为:0x%x\n",ep);
            return 0;
        }
    }

    /* 4.检查相邻的块是否都已经合并 */
    // for(ep=first_freeblock; ep!=NULL; ep=(char *)GET(LINKNEXT_BLKP(ep))){
    //     if(GET_ALLOC(HDRP(NEXT_BLKP(ep))) || GET_PREVALLOC(HDRP(ep))){
    //         printf("存在没有合并的相邻块!\n");
    //         return 0;
    //     }
    

    /* 检查所有块的地址是否满足8字节对齐 
     *  前提堆已经初始化,所以在mm_init中不能使用mm_check
     */
    
    for(ep=heap_listp + DSIZE; GET_SIZE(HDRP(ep))!=0; ep=(char *)NEXT_BLKP(ep)){
        if( (long)ep%8 != 0){
            printf("块的有效载荷开始地址 没有8字节对齐\n");
            return 0;
        }
    }
    
    return 1;
}


/*  void place(size_t words)     ------------------------ begin-------------------  */
/*   in list ==> suspended ==> allocated + (opntional:in list)    
 *   带有分配(allocated)能力,但不合并 不合并 不合并
 *   要求asize考虑了对齐和头尾长度
 */
static void place(void *bp, size_t asize)
{
            #ifdef DEBUG
                    printf(" ====> place(bp=0x%x, asize=%x)\n",bp, asize);
                    mm_check(__FUNCTION__);
            #endif // DEBUG
    
    size_t size = GET_SIZE(HDRP(bp));
    /* 1.统一处理:拆除逻辑链接 */
    Delete(bp);
    if(size < asize){
        fprintf(stderr, "*** *** place error!该块本身大小(0x%x)小于待分配值(0x%x)s*** *** ****\n\n", size, asize);
    }
    
    /* 分割后的大小满足最小快的要求 */
    if((size - asize) >= MINIBLK_SIZE){
        
        /* 分割后first block */
        PUT(HDRP(bp), PACK(asize, 1, GET_PREVALLOC(HDRP(bp)))) ;     //Header
        PUT(FTRP(bp), PACK(asize, 1, GET_PREVALLOC(HDRP(bp)))) ;     //footer
        /* 分割后的last block */
        PUT(HDRP(NEXT_BLKP(bp)), PACK(size - asize, 0, 1)) ;     //Header
        PUT(FTRP(NEXT_BLKP(bp)), PACK(size - asize, 0, 1)) ;     //footer
        /* 将此块的下一个块的prev_alloc不用进行设置,因为本来就为0(free) */
        /* 将分离后的last block 插入list */
        Insert(NULL, NEXT_BLKP(bp));        //与空闲块的数量成线性关系

        #ifdef DEBUG
        printf(" <==== place() 分割完成,被分离剩下的块地址_bp:0x%x, 大小:0x%x\n", NEXT_BLKP(bp), GET_SIZE(HDRP(NEXT_BLKP(bp))));
        #endif // DEBUG
        return ;

        // SET_NEXTBLKP_PREVALLOC(NEXT_BLKP(bp), 0);
    }else{
        /* 不需要分割 */
        PUT(HDRP(bp), PACK(GET_SIZE(HDRP(bp)), 1, GET_PREVALLOC(HDRP(bp))));    //header
        PUT(FTRP(bp), PACK(GET_SIZE(HDRP(bp)), 1, GET_PREVALLOC(HDRP(bp))));    //Footer
        SET_NEXTBLKP_PREVALLOC(bp, 1);          /* 将此块的下一个块的prev_alloc进行设置 */
        
        #ifdef DEBUG
        printf(" <====  place\n");
        printf("此块不需要分割\n\n\n ");
        #endif // DEBUG
        return ;
    }
}
/*  void place(size_t words)     -------------------- end -------------------------- */


/*  void *Whole_Coalesce( asize)                         ----- begin---------        */
/*  空闲表不能提供适当大小的空闲块时调用此函数
 *  边搜索边合并空闲块,return NULL if not find a proper free block
 */
static void *Whole_Coalesce(size_t size){
        #ifdef DEBUG
            printf(" ====> Whole_Coalesce(size:0x%x)\n", size);
            mm_check(__FUNCTION__);
        #endif // DEBUG
    char *bp = first_freeblock;
    /* case 1)list is empty */
    if(first_freeblock == NULL){
            #ifdef DEBUG
            mm_check(__FUNCTION__);
            printf(" <==== Whole_coalesce发现free list为空\n\n\n");
            #endif // DEBUG
        return NULL;
    }

    /* case 2)list isn't empty */
    while((void *)GET(LINKNEXT_BLKP(bp)) != NULL){  /* 遍历list */
        if(!GET_PREVALLOC(HDRP(bp)) || !GET_ALLOC(HDRP(NEXT_BLKP(bp))) ){   //该块可进行合并
            bp = Coalesce(bp);
            if(GET_SIZE(HDRP(bp)) >= size)
                #ifdef DEBUG
                printf(" <==== Whole_coalesce找到bp:0x%x,size:0x%x\n\n\n",bp ,size);
                #endif // DEBUG

                return (void *)bp;


        }else{
            /* 迭代 */
            bp = (void *)GET(LINKNEXT_BLKP(bp));
        }
    }
     #ifdef DEBUG
                printf(" <==== Whole_coalesce()未能找到0x%x 大小空间\n\n\n", size);
 #endif // DEBUG
    return NULL;
}
/*  void *Whole_Coalesce( asize)                         ----- end ---------        */



/*  void *find_fit( asize)                         ----- begin---------        */
/*  in list ==> in list 从list里面找出来一个大小合适的空闲块
 */
static  void *find_fit(size_t asize){
                #ifdef DEBUG
                    fprintf(stderr,"===> find_fit(asize:0x%x)\n", asize);
                    mm_check(__FUNCTION__);
                #endif // DEBUG

    char *bp = first_freeblock;
    for( ; bp != NULL; bp = (char *)GET(LINKNEXT_BLKP(bp))){
            if(GET_SIZE(HDRP(bp)) >= asize){
                
                    #ifdef DEBUG
                        fprintf(stderr," <==== find_fit()成功, 地址bp:0x%x 需要的asize:0x%x\n\n\n",bp, asize);
                    #endif // DEBUG

                return (void *)bp;
            }
    }
    #ifdef DEBUG
                fprintf(stderr," <==== find_fit未能找到合适的位置\n\n\n");
    #endif // DEBUG

    return NULL;
}
/*  void *find_fit( asize))                        ----- end  ---------        */



/*  void *Coalesce( bp)                         ----- begin---------        */
/*  in list ==> in list  Don‘t need "SET_NEXTBLKP_PREVALLOC"
 *  有多个Delete()语句时,先删除size小的,后删除大的
 *  必须记录最后一个Delete返回值,因为它才是有效的
 *  一次合并,不像核裂变一样持续进行
 */
static void *Coalesce(void *bp){
    char *start=(void *)mem_heap_lo(), *end=(void *)mem_heap_hi();
     
        #ifdef DEBUG
            printf(" ====> Coalesce(bp:0x%x)\n", bp);
            if(bp >= end || bp < start)
                printf("bp jumped the boundry of the heap!\n");
            mm_check(__FUNCTION__);
        #endif // DEBUG

    size_t prev_alloc = GET_PREVALLOC(HDRP(bp));
    size_t next_alloc = GET_ALLOC(HDRP(NEXT_BLKP(bp)));
    size_t new_prev_alloc;       // 放置合并后的新块的PREV_ALLOC
    char *insert_startp;
    // 前提:前面一个块是free状态
    size_t size_1 ;
    size_t size_2 = GET_SIZE(HDRP(bp));
    size_t size_3 ;

    /* case 1)前后皆Alloc */
    if( prev_alloc && next_alloc){
            #ifdef DEBUG
                printf(" <==== 无需合并,bp:0x%x\n\n\n", bp);
            #endif // DEBUG

        return bp;
    }
    
    /* case 2)前F 后A */
    if( !prev_alloc && next_alloc)
    {
        size_1 = GET_SIZE(HDRP(PREV_BLKP(bp)));
        if(size_1 > size_2){
            Delete(bp);
            insert_startp = Delete(PREV_BLKP(bp));
        }else{
            Delete(PREV_BLKP(bp));
            insert_startp = Delete(bp);
        }
        /* 1.物理——修改前一个块的大小 */
        // PREV_ALLOC要设置为前一个块的PREV_ALLOC
        new_prev_alloc = GET_PREVALLOC(HDRP(PREV_BLKP((bp))));
        PUT(HDRP(PREV_BLKP(bp)), PACK(size_1 + size_2, 0, new_prev_alloc));
        PUT(FTRP(PREV_BLKP(bp)), PACK(size_1 + size_2, 0, new_prev_alloc));
        
        /* 2.逻辑链接——还需要修改其一个块的指针 */
        Insert(insert_startp, PREV_BLKP(bp) );      //request "Insert" not to "Coalesce"

        #ifdef DEBUG
            printf(" <==== Coalesce()仅与前一个块(0x%x)合并\n\n\n", PREV_BLKP(bp));
        #endif // DEBUG

        return PREV_BLKP(bp);
    }

    /* case 3)前A 后F */
    if(prev_alloc && !next_alloc)
    {
         size_3 = GET_SIZE(HDRP(NEXT_BLKP(bp)));
         if(size_2 > size_3){
            Delete(NEXT_BLKP(bp));
            insert_startp = Delete(bp);
        }else{
            Delete(bp);
            insert_startp = Delete(NEXT_BLKP(bp));
        }
        /* 修改当前块大小 */                 /* +---前面一个块为A */
        PUT(HDRP(bp), PACK(size_2 + size_3, 0, 1));
        PUT(FTRP(bp), PACK(size_2 + size_3, 0, 1));
        Insert((void *)insert_startp, bp);
        #ifdef DEBUG
            printf(" <==== Coalesce()仅与后一个块(0x%x)合并\n\n\n", NEXT_BLKP(bp));
        #endif // DEBUG
        return bp;
    }

    /* case 4)F F F */
    if(!prev_alloc && !next_alloc)
    {
        void *prev_bp = PREV_BLKP(bp);
        void *next_bp = NEXT_BLKP(bp);
        size_1 = GET_SIZE(HDRP(PREV_BLKP(bp)));
        size_3 = GET_SIZE(HDRP(NEXT_BLKP(bp)));
        // PREV_ALLOC要设置为前一个块的PREV_ALLOC
        new_prev_alloc = GET_PREVALLOC(HDRP(prev_bp));
        /* 确保尺寸最大的块最后删除 */
        if(size_1 > size_2){
            Delete(bp);
            if(size_1 > size_3){
                Delete(next_bp);
                insert_startp = Delete(prev_bp);
            }else{
                Delete(prev_bp);
                insert_startp = Delete(next_bp);
            }
        }else{
            Delete(prev_bp);
            if(size_2 > size_3){
                Delete(next_bp);
                insert_startp = Delete(bp);
            }else{
                Delete(bp);
                insert_startp = Delete(next_bp);
            }
        }
        /* 修改新块大小 */
        PUT(HDRP(prev_bp), PACK(size_1 + size_2 +size_3, 0, new_prev_alloc) );   //header
        PUT(FTRP(prev_bp), PACK(size_1 + size_2 +size_3, 0, new_prev_alloc) );   //footer
        /* 插入到链表结构 suspended ==> in list */
        Insert(insert_startp, prev_bp);

            #ifdef DEBUG
                printf(" <==== Coalesce()与前(0x%x)后(0x%x)两个块合并\n\n\n", prev_bp, next_bp);
            #endif // DEBUG

        return prev_bp;
    }
}
/*  void *Coalesce( bp)                         ----- end---------        */



/*  void *Delete( bp)                         ----- begin---------        */
/* in list ==> suspended (alloc bit任)
 * 没有更改malloc bit
 * 返回被删除块的前一个块的地址,提高Insert插入速度
 * 若返回NULL,说明删除的是链表第一个元素
 * 可能出错的情况:空闲块链表为空,仍调用了Delete. 我尽量取避免,delete在coalese中,
 */
 static void *Delete(void *bp){

     char *next_bp, *prev_bp;
     size_t alloc=GET_ALLOC(HDRP(bp));

     #ifdef DEBUG
            printf(" ====> Delete(bp:0x%x)\n", bp);
            mm_check(__FUNCTION__);
            if(alloc){
                printf("*** *** Delete Error! Try to delete a allocated block!\n");
            }
    #endif // DEBUG
     
     if(first_freeblock == NULL){
         fprintf(stderr, "***  ***  *** Delete error!\n\n\n");
     }

     /* case 1)list中仅有一个元素 */ 
     if(bp == first_freeblock && (void *)GET(LINKNEXT_BLKP(bp)) == NULL){
        //后块 视 前块suspended状态为allcated
         SET_NEXTBLKP_PREVALLOC(bp, 1);      


                #ifdef DEBUG
                printf(" <==== Delete list中仅有一个元素\n\n\n");
                #endif // DEBUG
         
         return first_freeblock = NULL;
     }

     /* case 2)删除list的队头,块的个数大于1 */
     if(bp == first_freeblock){
         //后块 视 前块suspended状态为allcated
         SET_NEXTBLKP_PREVALLOC(bp, 1);
         PUT(LINKPREV_BLKP((void *)GET(LINKNEXT_BLKP(bp))), (void *)GET(LINKPREV_BLKP(bp)));
         first_freeblock = (char *)GET(LINKNEXT_BLKP(bp));
            #ifdef DEBUG
            printf(" <==== Delete 删除list的队头,块的个数大于1\n\n\n");
            #endif // DEBUG
         return NULL;
     }  

     /* case 3)删除list的队尾,块的个数大于1 */
     if((char *)GET(LINKNEXT_BLKP(bp)) == NULL){
        //后块 视 前块suspended状态为allcated
         SET_NEXTBLKP_PREVALLOC(bp, 1);
         PUT(LINKNEXT_BLKP((char *)GET(LINKPREV_BLKP(bp))), NULL);
         PUT(LINKPREV_BLKP(first_freeblock), (char *)GET(LINKPREV_BLKP(bp)));
        
                    #ifdef DEBUG
                        printf(" <==== Delete 删除list的队尾,块的个数大于1\n\n\n");
                    #endif // DEBUG
        
         return (void *)(GET(LINKPREV_BLKP(bp)));
     }

     /* case 4)删除list中间的元素 */
     //后块 视 前块suspended状态为allcated
     SET_NEXTBLKP_PREVALLOC(bp, 1);    
           
                    #ifdef DEBUG
                    printf(" Delete(bp:0x%x)  case 4)删除list中间的元素  \n", bp);
                    mm_check(__FUNCTION__);
                    #endif // DEBUG

     prev_bp = (char *)GET(LINKPREV_BLKP(bp));
     next_bp = (char *)GET(LINKNEXT_BLKP(bp));
     PUT(LINKNEXT_BLKP(prev_bp), next_bp);
     PUT(LINKPREV_BLKP(next_bp), prev_bp);
                    #ifdef DEBUG  
                            printf(" <==== Delete 删除list中间的元素\n\n\n");
                    #endif // DEBUG
     return (void *)prev_bp;
 }
/*  void *Delete( bp)                         ----- end  ---------        */



/*  void Insert( insert_startp, bp)          ----- begin---------        */
/*  suspended ==> in list   
 *  Coalesce 禁止Insert进行合并
 *  将suspended的alloc bit修改成0
 *  若insert_startp 为null则从链表头开始插入
 *  借助insert_startp指针方便在空闲链表快速插入bp(suspended) 
 */
 static void Insert(void *insert_startp, void* bp ){
    char *start=(void *)mem_heap_lo(), *end=(void *)mem_heap_hi();
     char *prev_bp, *ep;         //ep: explore pointer
     size_t need_size = GET_SIZE(HDRP(bp));
     ep = insert_startp;

        #ifdef DEBUG
            printf(" ====> insert(insert_startp:0x%x, bp:0x%x)\n",insert_startp, bp);
             mm_check(__FUNCTION__);
        if( insert_startp != NULL && (insert_startp < start || insert_startp > end  )) {
             printf("Insert中insert_startp的地址不正确:不在堆范围内!\n");    
        }
         #endif // DEBUG

     /* 2.4 Error: insert_startp!=NULL && first_freeblock == NULL
      * 链表不存在居然还有指针指向链表      
      */
      if(ep!=NULL && first_freeblock == NULL){
            fprintf(stderr, "*** *** Insert Error:链表不存在居然还有指针指向链表\n");
            exit(1);
      }
    /* 统一设置本块的alloc bit 为0 */
        PUT(HDRP(bp), PACK(GET_SIZE(HDRP(bp)), 0, GET_PREVALLOC(HDRP(bp))));
        PUT(FTRP(bp), PACK(GET_SIZE(HDRP(bp)), 0, GET_PREVALLOC(HDRP(bp))));

    /* 2.1 原explicit list为空 */
    if(first_freeblock == NULL && ep == NULL){
        first_freeblock = bp;
        PUT(LINKNEXT_BLKP(bp), NULL);       /* 将bp插入空表,并做好双向链接 */
        PUT(LINKPREV_BLKP(bp), bp);
        SET_NEXTBLKP_PREVALLOC(bp, 0);      //SET_Nextblock PREVALLOC

        #ifdef DEBUG
        printf(" <==== Insert; 原explicit free list为空\n\n\n");
        #endif // DEBUG

        return ;
    }

    /* now, first_freeblock ==> 非空 */
    /* 2.2, 2.3原链表有1个或多个块,根据适当的位置来插入 */
    /* 2.2 原链表仅有一个块 */
    if(ep == NULL){
        ep = first_freeblock;
    }

    /* 搜索被引上正道,寻找合适的插入位置,在ep前面插入,
     * 要求ep后的块大小大于等于bp的块大小 */
    while( ep!=NULL && GET_SIZE(HDRP(ep)) < need_size){
            ep = (char *)GET(LINKNEXT_BLKP(ep));        //向后迭代
    }
    
    /* a)没有比bp大的块,bp需要插入到非空链表的表尾tail */
    if(ep == NULL){
        PUT(LINKPREV_BLKP(bp), (char *)GET(LINKPREV_BLKP(first_freeblock)));
        PUT(LINKNEXT_BLKP((char *)GET(LINKPREV_BLKP(first_freeblock))), bp);
        PUT(LINKNEXT_BLKP(bp), NULL);
        PUT(LINKPREV_BLKP(first_freeblock), bp);
        SET_NEXTBLKP_PREVALLOC(bp, 0);              //SET_Nextblock PREVALLOC
            #ifdef DEBUG
                printf(" <==== Insert;bp(size:0x%x)插入到非空链表表尾\n\n\n", GET_SIZE(HDRP(bp)));
            #endif // DEBUG
        return ;
    }
    /* b)插入队头,无论空闲链表中有1个还是多个块       */
    if(ep == first_freeblock){
        PUT(LINKPREV_BLKP(bp), (char *)GET(LINKPREV_BLKP(first_freeblock)));
        PUT(LINKNEXT_BLKP(bp), first_freeblock);
        PUT(LINKPREV_BLKP(first_freeblock), bp);
        first_freeblock = bp;
        SET_NEXTBLKP_PREVALLOC(bp, 0);              //SET_Nextblock PREVALLOC
            #ifdef DEBUG
                printf(" <==== Insert;bp(size:0x%x)插入非空链表队头\n\n\n", GET_SIZE(HDRP(bp)));
            #endif // DEBUG
        
        return ;
    }
    /* c)插入队中,i.e前后都有块照应 */
    prev_bp = (char *)GET(LINKPREV_BLKP(ep));
    PUT(LINKPREV_BLKP(ep), bp);
    PUT(LINKNEXT_BLKP(bp), ep);
    PUT(LINKNEXT_BLKP(prev_bp), bp);
    PUT(LINKPREV_BLKP(bp), prev_bp);
    SET_NEXTBLKP_PREVALLOC(bp, 0);               //SET_Nextblock PREVALLOC

            #ifdef DEBUG
                printf(" <==== Insert;bp(size:0x%x)插入非空链表中间\n\n\n", GET_SIZE(HDRP(bp)));
            #endif // DEBUG

    return ; 
 }
/*  void Insert( insert_startp, bp)                -----  end  ---------        */



/*  *extend_heap( words)          ----- begin---------        */
/* 拓展堆words个字,以字为单位   suspended ==> in list
 * 拓展要多少空间就分配多少空间,决不能打折,也不能合并!! 
 * 带有合并(coalesce)能力,这里拓展堆没有采用MAX(CHUNKSIZE,~)机制,看能否throuput better
 */
 static void *extend_heap(size_t words)
 {            
     char *bp, *heap_hi_bdy = (char *)mem_heap_hi() +1; //堆最大的地址加1
     size_t  size, prev_alloc= GET_PREVALLOC(HDRP(heap_hi_bdy));           
     /* 满足2字 alignment */
     size = (words%2) ? (words+1)*WSIZE : words*WSIZE;
     
         #ifdef DEBUG
            printf(" ====> extend_heap(words:%u = 0x%x Byte)\n", words, words*WSIZE);
            mm_check(__FUNCTION__);
        #endif

     /* 要多少空间就分配多少空间 */
         if((long)(bp = mem_sbrk(size))  == -1)
            return NULL;
         /* 释放old结尾块,其成为suspended state */
         PUT(HDRP(bp), PACK(size, 0, prev_alloc));
         PUT(FTRP(bp), PACK(size, 0, prev_alloc));
         /* 更新 新结尾块 */
         PUT( HDRP(NEXT_BLKP(bp)), PACK(0, 1, 0));  //prev_alloc = 0;
        /* 将准备待续的suspended块插入free list */
         /*
          *可能空间刚好用完==>first_freeblock可能为NULL
          *if(first_freeblock == NULL)                    
          *      Insert( NULL, bp);
          *else 
          *     suspended块必定插入在free list的尾部 
          *     Insert( (void *)GET(LINKPREV_BLKP(first_freeblock)), bp);      // 
          *
          */ 

          // 保守做法,从前面插入  时间复杂度高,与空闲块的数量成正比 ——可以提高、改进
          Insert( NULL, bp);
          
           
            #ifdef DEBUG
                printf(" <==== extend_heap(); 返回值:0x%x\n\n\n", (void *)bp);
            #endif
         
         return (void *)bp;
        

     

 }
/*  *extend_heap()          -----  end  ---------        */


/* 
 * mm_init - initialize the malloc package.
 */
int mm_init(void)
{
            #ifdef DEBUG
            printf(" ====>  mm_init()\n"); 
            #endif // DEBUG
    char *bp;
    if( (heap_listp = mem_sbrk(4 * WSIZE))  == (void *)-1 ) 
         return -1;
    
    PUT(heap_listp, 0);                             //Alignment padding
    PUT(heap_listp + (1 * WSIZE), PACK(8, 1, 1));   //prologue header
    PUT(heap_listp + (2 * WSIZE), PACK(8, 1, 1));   //prologue footer
    PUT(heap_listp + (3 * WSIZE), PACK(0, 1, 1));   //epilogue 
    if(extend_heap(CHUNKSIZE/WSIZE) ==NULL ){
             #ifdef DEBUG     
               printf("*** *** mm_init: Error! extend_heap()调用失败\n"); 
             #endif // DEBUG
        return -1;
    }

    heap_listp += DSIZE;

    /* Set the first free block in the heap, and set link in the explicit link list */
    first_freeblock = heap_listp + DSIZE;
    bp = first_freeblock;
    PUT(HDRP(bp), PACK(CHUNKSIZE, 0, 1 ));          //SET first block header
    PUT(FTRP(bp), PACK(CHUNKSIZE, 0, 1 ));          //SET first block footer
    PUT(LINKNEXT_BLKP(bp), NULL);                   //设置双向链表,prev指向自己,next指向NULL
    PUT(LINKPREV_BLKP(bp), bp); 
    SET_NEXTBLKP_PREVALLOC(bp, 0);
    #ifdef DEBUG     
      printf(" <==== mm_init(); fisrt_freeblock:0x%x\n\n\n", first_freeblock); 
    #endif // DEBUG
    return 0;
}
/* mm_init()     ------     end        --------------  */  


/* 
 * mm_malloc - Allocate a block by incrementing the brk pointer.
 *     Always allocate a block whose size is a multiple of the alignment.
 *  返回的有效载荷必须8字节对齐,载荷大小也需要对齐才能保证前者
 */
void *mm_malloc(size_t size)
{
        #ifdef DEBUG
            printf(" ====> malloc(size:0x%x)\n\n\n", size);
            mm_check(__FUNCTION__);
        #endif // DEBUG
    size_t newsize = ALIGN(size), prev_size, extend_size, epilogue_prevalloc;        
    //newsize还包括overhead,对齐
    char *bp, *prev_bp, *heap_hi_bdy =(char *)mem_heap_hi() +1;
    /* Ignore spuring request */
    if(size == 0) {
    return NULL;
    }

    /* 调整块大小,满足头部的开销和对齐要求 */
    if(newsize <= MINIBLK_SIZE){           //最小块大小
        newsize =  MINIBLK_SIZE;
    }

    /* 第一次找到合适的块 */
    if((bp = find_fit(newsize)) != NULL){
        place(bp, newsize);

        #ifdef DEBUG
            printf(" <==== malloc(); 第一次找到合适的地址bp: 0x%x, 共0x%xBytes\n\n\n", bp, newsize);
        #endif // DEBUG
        
        return bp;
    }

    /* 第一次没找到,边合并边进行第二次查找 */
   
    if((bp = Whole_Coalesce(newsize)) != NULL){ 

        place(bp, newsize);

        #ifdef DEBUG
            printf(" <==== malloc(); 第二次寻找成功,返回地址bp: 0x%x, 共0x%xBytes\n\n\n", bp, newsize);
         #endif // DEBUG
        return bp;


    }

    /* 两次都没有找到 */
    // epilogue_prevalloc = GET_PREVALLOC(HDRP((char *)mem_heap_hi() + 1) );
    // /* 若结尾块的前一个块为free则可以减少此次申请的空间 */
    // /*  直接考虑总大小        */
    // if(!epilogue_prevalloc){
    //     //  仅前面的块未分配才能得知它的地址及大小by NEXT_BLKP()
    //      prev_bp = PREV_BLKP(heap_hi_bdy);
    //      prev_size = GET_SIZE(HDRP(prev_bp));
    //     #ifdef DEBUG
    //      if(newsize <= prev_size){
    //          printf(" *** *** malloc错误!旧结尾块前的空闲块(0x%x)的大小能胜任\n", 
    //                     PREV_BLKP((char *)mem_heap_hi() + 1));
    //      }
    //     #endif // DEBUG

    //     extend_size =  newsize - prev_size; 
    //     #ifdef DEBUG
    //      if(prev_size%8 != 0){
    //          printf(" *** *** malloc错误!旧结尾块前的空闲块大小没有八字节对齐\n");   
    //      }
    //     #endif // DEBUG
    //     //ALIGN(extend_size);

    //     if((bp = extend_heap(extend_size/WSIZE)) == NULL){
    //             #ifdef DEBUG
    //                 printf(" *** *** malloc错误:调用extend_heap失败!\n");
    //             #endif // DEBUG
    //         return NULL;                                 //malloc fail
    //     }
    //     //进行合并
    //     bp = Coalesce(bp);
    //     //借用place的分配能力
    //     place(bp, newsize);                
    
    //         #ifdef DEBUG
    //         printf(" <==== malloc();分配成功,返回值bp: 0x%x  size : 0x%x\n\n\n", bp, newsize);
    //         #endif // DEBUG
    //     return (void *)bp;   
    // }
    // else
    {
        extend_size = newsize;
        if((bp = extend_heap(extend_size/WSIZE)) == NULL){
            #ifdef DEBUG
            printf(" *** *** malloc错误:调用extend_heap失败!\n");
            #endif // DEBUG
            return NULL;                                 //malloc fail
        }
        place(bp, newsize);                //借用place的分配能力

            #ifdef DEBUG
            printf(" <==== malloc();分配成功,返回值bp: 0x%x  size : 0x%x\n\n\n", bp, newsize);
            #endif // DEBUG
        return (void *)bp;
    }
    //return (void *)((char *)p + SIZE_T_SIZE);  能够实行不同的系统size_t的大小


    
    
}


/*  mm_free -----------------------------  begfin  ----------------------------- */
/*
 * mm_free - Freeing a block does nothing.
 * allcated ==> suspended ==> in list
 */
void mm_free(void *ptr)
{
    #ifdef DEBUG
    printf(" ====> free(0x%x)\n", ptr);
   
    #endif // DEBUG
    
    if(ptr == NULL){
        return ;
    }
    /* 1.物理结构改成未分配, ==>suspended */
    PUT(HDRP(ptr), PACK(GET_SIZE(HDRP(ptr)), 0, GET_PREVALLOC(HDRP(ptr))));    //Header
    PUT(FTRP(ptr), PACK(GET_SIZE(HDRP(ptr)), 0, GET_PREVALLOC(HDRP(ptr))));    //footer
    /* 2.插入逻辑链表, 建立link    */
    Insert(NULL, ptr);
           
    /* 3.合并一次           */
    Coalesce(ptr);                       //延迟合并,可以改成立即合并

    #ifdef DEBUG
    printf(" <==== free(0x%x)\n", ptr);
    printf("\n\n\n", ptr);
    #endif // DEBUG
}
/*  mm_free -----------------------------  end  ----------------------------- */


/*
 * mm_realloc - Implemented simply in terms of mm_malloc and mm_free
 */
void *mm_realloc(void *ptr, size_t size)
{   
    #ifdef DEBUG
    mm_check(__FUNCTION__);
    #endif // DEBUG
    
    void *oldptr = ptr;
    void *newptr;
    size_t copySize, old_size, asize, e_size;// e_size:effective size of the old block
   
    old_size = GET_SIZE(HDRP(ptr));
    e_size = old_size - WSIZE;
    asize = ALIGN(size + WSIZE);
    /* Very Important! because malloc(1)==>realloc(2) */
    /* malloc(8)==>realloc(9)
     * ml(24) == > ralc(25)
     *  Note: We don't konw how much part of the bolck is in use. The core of the problem
     * is ROUND UP
     *  Solution: Only the the old_size is smaller than asize, we do nothing,
     *  or we need to find a new block 
     */

   
    /* case 1: ptr is NULL */
    if(ptr == NULL)
        return mm_malloc(size);

    // ptr is not NULL
    /* case 2: size is equal to zero */
    if(size == 0)
        mm_free(ptr);

    /* case 3: change the size of the block */
    //  3.1 Directly Set in the new place       
    
   
    if(e_size < size ){
      // 新块大小大于旧块,有可能太大分配不了
        //  0.Out of memory
        //  1.新分配一块区域
        if((newptr=mm_malloc(size)) == NULL){
            return NULL;
        }
        //  2.将数据复制到新区域
        copySize = old_size-WSIZE;
        memcpy(newptr, oldptr, copySize);
        //  3.释放旧块
        mm_free(oldptr);
        return newptr;
    }
    
    //3.2 Splitted the block if the old size is bigger than old size 16B or more
    if(old_size >= asize + MINIBLK_SIZE){
        // 分割后剩下的块满足最小的块大小,应该被分离出来
        //  1.分割旧块,设置旧块头部+后块PREV_ALLOC(由后块自己完成)
        PUT(HDRP(ptr), PACK(asize, 1, GET_PREVALLOC(HDRP(ptr))));
        //  2.设置被剩下块的头部和脚部+后块PREV_ALLOC,然后插入free list
        PUT(HDRP(NEXT_BLKP(ptr)), PACK(old_size-asize, 0, 1));  //suspended ==>  in list
        mm_free(NEXT_BLKP(ptr));
        return ptr;
    }
    //3.3 Conservative action:reset the old block
    // do nothing
    
        return ptr;

    
  
    
}

/* help function */


/* 设置此块的下一块的PREV_ALLOC位为1或0, 常用*/
static void SET_NEXTBLKP_PREVALLOC(char *bp, size_t val){
    char *next_bp = (NEXT_BLKP(bp));
    PUT(HDRP(next_bp), PACK(GET_SIZE(HDRP(next_bp)), GET_ALLOC(HDRP(next_bp)), val));
    if(GET_SIZE(HDRP(next_bp)) != 0)       /* not epilogue padding */
    PUT(FTRP(next_bp), PACK(GET_SIZE(HDRP(next_bp)), GET_ALLOC(HDRP(next_bp)), val));
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值