Blame | Last modification | View Log | Download | RSS feed
/** Simple, 32-bit and 64-bit clean allocator based on implicit free* lists, first fit placement, and boundary tag coalescing, as described* in the CS:APP2e text. Blocks must be aligned to doubleword (8 byte)* boundaries. Minimum block size is 16 bytes.** This version is loosely based on* http://csapp.cs.cmu.edu/public/ics2/code/vm/malloc/mm.c* but unlike the book's version, it does not use C preprocessor* macros or explicit bit operations.*/#include <stdio.h>#include <string.h>#include <stdlib.h>#include <stdbool.h>#include <stdint.h>#include <stddef.h>#include <assert.h>#include "mm.h"#include "memlib.h"struct boundary_tag {int inuse:1; // inuse bitint size:31; // size of block, in words};/* FENCE is used for heap prologue/epilogue. */const struct boundary_tag FENCE = { .inuse = 1, .size = 0 };/* A C struct describing the beginning of each block.* For implicit lists, used and free blocks have the same* structure, so one struct will suffice for this example.* If each block is aligned at 4 mod 8, each payload will* be aligned at 0 mod 8.*/struct block {struct boundary_tag header; /* offset 0, at address 4 mod 8 */char payload[0]; /* offset 4, at address 0 mod 8 */};/** If NEXT_FIT defined use next fit search, else use first fit search*/#define NEXT_FITx/* Basic constants and macros */#define WSIZE 4 /* Word and header/footer size (bytes) */#define DSIZE 8 /* Doubleword size (bytes) */#define MIN_BLOCK_SIZE_WORDS 4 /* Minimum block size in words */#define CHUNKSIZE (1<<10) /* Extend heap by this amount (words) */#define MAX(x, y) ((x) > (y)? (x) : (y))/* Global variables */static struct block *heap_listp = 0; /* Pointer to first block */#ifdef NEXT_FITstatic struct block *rover; /* Next fit rover */#endif/* Function prototypes for internal helper routines */static struct block *extend_heap(size_t words);static void place(struct block *bp, size_t asize);static struct block *find_fit(size_t asize);static struct block *coalesce(struct block *bp);/* Given a block, obtain previous's block footer.Works for left-most block also. */static struct boundary_tag * prev_blk_footer(struct block *blk) {return &blk->header - 1;}/* Return if block is free */static bool blk_free(struct block *blk) {return !blk->header.inuse;}/* Return size of block is free */static size_t blk_size(struct block *blk) {return blk->header.size;}/* Given a block, obtain pointer to previous block.Not meaningful for left-most block. */static struct block *prev_blk(struct block *blk) {struct boundary_tag *prevfooter = prev_blk_footer(blk);assert(prevfooter->size != 0);return (struct block *)((size_t *)blk - prevfooter->size);}/* Given a block, obtain pointer to next block.Not meaningful for right-most block. */static struct block *next_blk(struct block *blk) {assert(blk_size(blk) != 0);return (struct block *)((size_t *)blk + blk->header.size);}/* Given a block, obtain its footer boundary tag */static struct boundary_tag * get_footer(struct block *blk) {return (void *)((size_t *)blk + blk->header.size)- sizeof(struct boundary_tag);}/* Set a block's size and inuse bit in header and footer */static void set_header_and_footer(struct block *blk, int size, int inuse) {blk->header.inuse = inuse;blk->header.size = size;* get_footer(blk) = blk->header; /* Copy header to footer */}/* Mark a block as used and set its size. */static void mark_block_used(struct block *blk, int size) {set_header_and_footer(blk, size, 1);}/* Mark a block as free and set its size. */static void mark_block_free(struct block *blk, int size) {set_header_and_footer(blk, size, 0);}/** mm_init - Initialize the memory manager*/int mm_init(void){/* Create the initial empty heap */struct boundary_tag * initial = mem_sbrk(2 * sizeof(struct boundary_tag));if (initial == (void *)-1)return -1;/* We use a slightly different strategy than suggested in the book.* Rather than placing a min-sized prologue block at the beginning* of the heap, we simply place two fences.* The consequence is that coalesce() must call prev_blk_footer()* and not prev_blk() - prev_blk() cannot be called on the left-most* block.*/initial[0] = FENCE; /* Prologue footer */heap_listp = (struct block *)&initial[1];initial[1] = FENCE; /* Epilogue header */#ifdef NEXT_FITrover = heap_listp;#endif/* Extend the empty heap with a free block of CHUNKSIZE bytes */if (extend_heap(CHUNKSIZE) == NULL)return -1;return 0;}/** mm_malloc - Allocate a block with at least size bytes of payload*/void *mm_malloc(size_t size){size_t awords; /* Adjusted block size in words */size_t extendwords; /* Amount to extend heap if no fit */struct block *bp;if (heap_listp == 0){mm_init();}/* Ignore spurious requests */if (size == 0)return NULL;/* Adjust block size to include overhead and alignment reqs. */size += 2 * sizeof(struct boundary_tag); /* account for tags */size = (size + DSIZE - 1) & ~(DSIZE - 1); /* align to double word */awords = MAX(MIN_BLOCK_SIZE_WORDS, size/WSIZE);/* respect minimum size *//* Search the free list for a fit */if ((bp = find_fit(awords)) != NULL) {place(bp, awords);return bp->payload;}/* No fit found. Get more memory and place the block */extendwords = MAX(awords,CHUNKSIZE);if ((bp = extend_heap(extendwords)) == NULL)return NULL;place(bp, awords);return bp->payload;}/** mm_free - Free a block*/void mm_free(void *bp){if (bp == 0)return;/* Find block from user pointer */struct block *blk = bp - offsetof(struct block, payload);if (heap_listp == 0) {mm_init();}mark_block_free(blk, blk_size(blk));coalesce(blk);}/** coalesce - Boundary tag coalescing. Return ptr to coalesced block*/static struct block *coalesce(struct block *bp){bool prev_alloc = prev_blk_footer(bp)->inuse;bool next_alloc = ! blk_free(next_blk(bp));size_t size = blk_size(bp);if (prev_alloc && next_alloc) { /* Case 1 */return bp;}else if (prev_alloc && !next_alloc) { /* Case 2 */mark_block_free(bp, size + blk_size(next_blk(bp)));}else if (!prev_alloc && next_alloc) { /* Case 3 */bp = prev_blk(bp);mark_block_free(bp, size + blk_size(bp));}else { /* Case 4 */mark_block_free(prev_blk(bp),size + blk_size(next_blk(bp)) + blk_size(prev_blk(bp)));bp = prev_blk(bp);}#ifdef NEXT_FIT/* Make sure the rover isn't pointing into the free block *//* that we just coalesced */if ((rover > bp) && (rover < next_blk(bp)))rover = bp;#endifreturn bp;}/** 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. */struct block *oldblock = ptr - offsetof(struct block, payload);oldsize = blk_size(oldblock) * WSIZE;if(size < oldsize) oldsize = size;memcpy(newptr, ptr, oldsize);/* Free the old block. */mm_free(ptr);return newptr;}/** checkheap - We don't check anything right now.*/void mm_checkheap(int verbose){}/** The remaining routines are internal helper routines*//** extend_heap - Extend heap with free block and return its block pointer*/static struct block *extend_heap(size_t words){void *bp;/* Allocate an even number of words to maintain alignment */words = (words + 1) & ~1;if ((long)(bp = mem_sbrk(words * WSIZE)) == -1)return NULL;/* Initialize free block header/footer and the epilogue header.* Note that we scoop up the previous epilogue here. */struct block * blk = bp - sizeof(FENCE);mark_block_free(blk, words);next_blk(blk)->header = FENCE;/* Coalesce if the previous block was free */return coalesce(blk);}/** place - Place block of asize words at start of free block bp* and split if remainder would be at least minimum block size*/static void place(struct block *bp, size_t asize){size_t csize = blk_size(bp);if ((csize - asize) >= MIN_BLOCK_SIZE_WORDS) {mark_block_used(bp, asize);bp = next_blk(bp);mark_block_free(bp, csize-asize);}else {mark_block_used(bp, csize);}}/** find_fit - Find a fit for a block with asize words*/static struct block *find_fit(size_t asize){#ifdef NEXT_FIT/* Next fit search */struct block *oldrover = rover;/* Search from the rover to the end of list */for ( ; blk_size(rover) > 0; rover = next_blk(rover))if (blk_free(rover) && (asize <= blk_size(rover)))return rover;/* search from start of list to old rover */for (rover = heap_listp; rover < oldrover; rover = next_blk(rover))if (blk_free(rover) && (asize <= blk_size(rover)))return rover;return NULL; /* no fit found */#else/* First fit search */struct block *bp;for (bp = heap_listp; blk_size(bp) > 0; bp = next_blk(bp)) {if (blk_free(bp) && asize <= blk_size(bp)) {return bp;}}return NULL; /* No fit */#endif}team_t team = {/* Team name */"Sample allocator using implicit lists",/* First member's full name */"Godmar Back","gback@cs.vt.edu",/* Second member's full name (leave blank if none) */"","",};