(CSAPP第三版系列)导航篇传送门
9.12 对于下面的地址,重复习题9.11:
虚拟地址: 0x03a9A. 虚拟地址格式
B. 地址翻译
参数 |
值 |
VPN |
0xE |
TLB索引 |
0x2 |
TLB标记 |
0x3 |
TLB命中?(是/否) |
否 |
缺页?(是/否) |
否 |
PPN |
0x11 |
D. 物理地址引用
参数 |
值 |
字节偏移 |
0x1 |
缓存索引 |
0xA |
缓存标记 |
0x11 |
缓存命中?(是/否) |
否 |
返回的缓存字节 |
—— |
9.14 编写一个C程序,使用mmap将hello.txt的内容改变为“Jello,world!\n”。
程序如下(已经过运行测试):
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <sys/mman.h> int main() { int fd = open("hello.txt",O_RDWR,0); char *start = mmap(NULL,1,PROT_WRITE,MAP_SHARED,fd,0); close(fd); if(start == MAP_FAILED) printf("error!\n"); else { *start = 'J'; munmap(start,1); return 0; } }
对齐要求 |
已分配块 |
空闲块 |
最小块大小(字节) |
单字 |
头部和脚部 |
头部和脚部 |
16 |
单字 |
头部,但是没有脚部 |
头部和脚部 |
12 |
双字 |
头部和脚部 |
头部和脚部 |
16 |
双字 |
头部,但是没有脚部 |
头部和脚部 |
16 |
9.18修改分配器,使得空闲块需要头部和脚部,而已分配块只需要头部。
mm.c文件:
#include <stdio.h> #include <string.h> #include <stdlib.h> #include "mm.h" #include "memlib.h" /* $begin mallocmacros */ /* Basic constants and macros */ #define WSIZE 4 /* Word and header/footer size (bytes) */ //line:vm:mm:beginconst #define DSIZE 8 /* Double word size (bytes) */ #define CHUNKSIZE (1<<12) /* Extend heap by this amount (bytes) */ //line:vm:mm:endconst #define MAX(x, y) ((x) > (y)? (x) : (y)) /* Pack a size and allocated bit into a word */ #define PACK(size, alloc) ((size) | (alloc)) //line:vm:mm:pack /* Read and write a word at address p */ #define GET(p) (*(unsigned int *)(p)) //line:vm:mm:get #define PUT(p, val) (*(unsigned int *)(p) = (val)) //line:vm:mm:put /* Read the size and allocated fields from address p */ #define GET_SIZE(p) (GET(p) & ~0x7) //line:vm:mm:getsize #define GET_ALLOC(p) (GET(p) & 0x1) //line:vm:mm:getalloc #define GET_PREVIOUS_ALLOC(p) (GET(p) & 0x2) /* ! CHANGED ! */ /* Given block ptr bp, compute address of its header and footer */ #define HDRP(bp) ((char *)(bp) - WSIZE) //line:vm:mm:hdrp #define FTRP(bp) ((char *)(bp) + GET_SIZE(HDRP(bp)) - DSIZE) //line:vm:mm:ftrp /* Given block ptr bp, compute address of next and previous blocks */ #define NEXT_BLKP(bp) ((char *)(bp) + GET_SIZE(((char *)(bp) - WSIZE))) //line:vm:mm:nextblkp #define PREV_BLKP(bp) ((char *)(bp) - GET_SIZE(((char *)(bp) - DSIZE))) //line:vm:mm:prevblkp /* $end mallocmacros */ /* Global variables */ static char *heap_listp = 0; /* Pointer to first block */ static char *rover; /* Next fit rover */ /* Function prototypes for internal helper routines */ static void *extend_heap(size_t words); static void place(void *bp, size_t asize); static void *find_fit(size_t asize); static void *coalesce(void *bp); /* * mm_init - Initialize the memory manager */ /* $begin mminit */ int mm_init(void) { /* Create the initial empty heap */ if ((heap_listp = mem_sbrk(4*WSIZE)) == (void *)-1) //line:vm:mm:begininit return -1; PUT(heap_listp, 0); /* Alignment padding */ PUT(heap_listp + (1*WSIZE), PACK(DSIZE, 0x1 | 0x2)); /* Prologue header */ PUT(heap_listp + (2*WSIZE), PACK(DSIZE, 0x1 | 0x2)); /* Prologue footer */ PUT(heap_listp + (3*WSIZE), PACK(0, 0x1 | 0x2)); /* Epilogue header */ heap_listp += (2*WSIZE); //line:vm:mm:endinit /* $end mminit */ rover = heap_listp; /* $begin mminit */ /* Extend the empty heap with a free block of CHUNKSIZE bytes */ if (extend_heap(CHUNKSIZE/WSIZE) == NULL) return -1; return 0; } /* $end mminit */ /* * mm_malloc - Allocate a block with at least size bytes of payload */ /* $begin mmmalloc */ void *mm_malloc(size_t size) { size_t Wsize; /* round up to an WSIZE */ /* ! CHANGED ! */ size_t Dsize; /* DSIZE after align WSIZE */ /* ! CHANGED ! */ size_t asize; /* Adjusted block size */ size_t extendsize; /* Amount to extend heap if no fit */ char *bp; /* $end mmmalloc */ if (heap_listp == 0){ mm_init(); } /* $begin mmmalloc */ /* Ignore spurious requests */ if (size == 0) return NULL; Wsize = (size + (WSIZE-1)) / WSIZE; /* ! CHANGED ! */ Dsize = Wsize/2 + 1; /* ! CHANGED ! */ asize = DSIZE * Dsize; /* ! CHANGED ! */ /* Search the free list for a fit */ if ((bp = find_fit(asize)) != NULL) { //line:vm:mm:findfitcall place(bp, asize); //line:vm:mm:findfitplace return bp; } /* No fit found. Get more memory and place the block */ extendsize = MAX(asize,CHUNKSIZE); //line:vm:mm:growheap1 if ((bp = extend_heap(extendsize/WSIZE)) == NULL) return NULL; //line:vm:mm:growheap2 place(bp, asize); //line:vm:mm:growheap3 return bp; } /* $end mmmalloc */ /* * mm_free - Free a block */ /* $begin mmfree */ void mm_free(void *bp) { /* $end mmfree */ if (bp == 0) return; /* $begin mmfree */ size_t size = GET_SIZE(HDRP(bp)); /* $end mmfree */ if (heap_listp == 0){ mm_init(); } /* $begin mmfree */ if (GET_PREVIOUS_ALLOC(HDRP(bp))) /* ! CHANGED ! */ { PUT(HDRP(bp), PACK(size, 0x2)); } else { PUT(HDRP(bp), PACK(size, 0)); } PUT(FTRP(bp), PACK(size, 0)); /* ! CHANGED ! */ /* pack next block */ *HDRP(NEXT_BLKP(bp)) &= ~0x2; /* ! CHANGED ! */ coalesce(bp); } /* $end mmfree */ /* * coalesce - Boundary tag coalescing. Return ptr to coalesced block */ /* $begin mmfree */ static void *coalesce(void *bp) { size_t prev_alloc = GET_PREVIOUS_ALLOC(HDRP(bp)); /* ! CHANGED ! */ size_t next_alloc = GET_ALLOC(HDRP(NEXT_BLKP(bp))); size_t size = GET_SIZE(HDRP(bp)); if (prev_alloc && next_alloc) { /* Case 1 */ return bp; } else if (prev_alloc && !next_alloc) { /* Case 2 */ size += GET_SIZE(HDRP(NEXT_BLKP(bp))); PUT(HDRP(bp), PACK(size, 0x2)); /* ! CHANGED ! */ PUT(FTRP(bp), PACK(size,0)); /* ! CHANGED ! */ } else if (!prev_alloc && next_alloc) { /* Case 3 */ size += GET_SIZE(HDRP(PREV_BLKP(bp))); PUT(FTRP(bp), PACK(size, 0)); if (GET_PREVIOUS_ALLOC(HDRP(PREV_BLKP(bp)))) /* ! CHANGED ! */ { PUT(HDRP(PREV_BLKP(bp)), PACK(size, 0x2)); } else { PUT(HDRP(PREV_BLKP(bp)), PACK(size, 0)); } bp = PREV_BLKP(bp); /* ! CHANGED ! */ } else { /* Case 4 */ size += GET_SIZE(HDRP(PREV_BLKP(bp))) + GET_SIZE(FTRP(NEXT_BLKP(bp))); if (GET_PREVIOUS_ALLOC(HDRP(PREV_BLKP(bp)))) /* ! CHANGED ! */ { PUT(HDRP(PREV_BLKP(bp)), PACK(size, 0x2)); } else { PUT(HDRP(PREV_BLKP(bp)), PACK(size, 0)); } PUT(FTRP(NEXT_BLKP(bp)), PACK(size, 0)); bp = PREV_BLKP(bp); } /* $end mmfree */ /* Make sure the rover isn't pointing into the free block */ /* that we just coalesced */ if ((rover > (char *)bp) && (rover < NEXT_BLKP(bp))) rover = bp; /* $begin mmfree */ return bp; } /* $end mmfree */ /* * mm_realloc - Naive implementation of realloc */ void *mm_realloc(void *ptr, size_t size) { size_t oldsize; void *newptr; /* If size == 0 then this is just free, and we return NULL. */ if(size == 0) { mm_free(ptr); return 0; } /* If oldptr is NULL, then this is just malloc. */ if(ptr == NULL) { return mm_malloc(size); } newptr = mm_malloc(size); /* If realloc() fails the original block is left untouched */ if(!newptr) { return 0; } /* Copy the old data. */ oldsize = GET_SIZE(HDRP(ptr)); if(size < oldsize) oldsize = size; memcpy(newptr, ptr, oldsize); /* Free the old block. */ mm_free(ptr); return newptr; } /* * The remaining routines are internal helper routines */ /* * extend_heap - Extend heap with free block and return its block pointer */ /* $begin mmextendheap */ static void *extend_heap(size_t words) { char *bp; size_t size; /* Allocate an even number of words to maintain alignment */ size = (words % 2) ? (words+1) * WSIZE : words * WSIZE; //line:vm:mm:beginextend if ((long)(bp = mem_sbrk(size)) == -1) return NULL; //line:vm:mm:endextend /* Initialize free block header/footer and the epilogue header */ if (GET_PREVIOUS_ALLOC(HDRP(bp))) /* ! CHANGED ! */ { PUT(HDRP(bp), PACK(size, 0x2)); } else { PUT(HDRP(bp), PACK(size, 0)); } PUT(FTRP(bp), PACK(size, 0)); /* Free block footer */ //line:vm:mm:freeblockftr PUT(HDRP(NEXT_BLKP(bp)), PACK(0, 1)); /* New epilogue header */ //line:vm:mm:newepihdr /* Coalesce if the previous block was free */ return coalesce(bp); //line:vm:mm:returnblock } /* $end mmextendheap */ /* * place - Place block of asize bytes at start of free block bp * and split if remainder would be at least minimum block size */ /* $begin mmplace */ /* $begin mmplace-proto */ static void place(void *bp, size_t asize) /* $end mmplace-proto */ { size_t csize = GET_SIZE(HDRP(bp)); if ((csize - asize) >= DSIZE) { /* ! CHANGED ! */ if (GET_PREVIOUS_ALLOC(HDRP(bp))) /* ! CHANGED ! */ { PUT(HDRP(bp), PACK(asize, 0x2|0x1)); } else { PUT(HDRP(bp), PACK(asize, 0x1)); } PUT(FTRP(bp), PACK(asize, 1)); bp = NEXT_BLKP(bp); PUT(HDRP(bp), PACK(csize-asize, 0x2)); /* ! CHANGED ! */ PUT(FTRP(bp), PACK(csize-asize, 0)); } else { if (GET_PREVIOUS_ALLOC(HDRP(bp))) /* ! CHANGED ! */ { PUT(HDRP(bp), PACK(csize, 0x2|0x1)); } else { PUT(HDRP(bp), PACK(csize, 0x1)); } PUT(FTRP(bp), PACK(csize, 1)); /* ! CHANGED ! */ *HDRP(NEXT_BLKP(bp)) |= 0x2; /* ! CHANGED ! */ } } /* $end mmplace */ /* * find_fit - Find a fit for a block with asize bytes */ static void *find_fit(size_t asize) { /* Next fit search */ char *oldrover = rover; /* Search from the rover to the end of list */ for ( ; GET_SIZE(HDRP(rover)) > 0; rover = NEXT_BLKP(rover)) if (!GET_ALLOC(HDRP(rover)) && (asize <= GET_SIZE(HDRP(rover)))) return rover; /* search from start of list to old rover */ for (rover = heap_listp; rover < oldrover; rover = NEXT_BLKP(rover)) if (!GET_ALLOC(HDRP(rover)) && (asize <= GET_SIZE(HDRP(rover)))) return rover; return NULL; /* no fit found */ } /* $end mmfirstfit */