/* * mm_checkheap */ void mm_checkheap(int lineno) { lineno = lineno; int free_count = 0; int freelist_count = 0; void *bp; for (bp = free_listp; GET_SIZE(HDRP(bp)) > 0; bp = NEXT_FREE_BLKP(bp)) { if (GET_ALLOC(bp)) printf("Allocated block in free list!\n"); if (!aligned(bp)) printf("Base pointer in heap is not aligned!\n"); if (!in_heap(NEXT_FREE_BLKP(bp)) || !in_heap(PREV_FREE_BLKP(bp))) printf("Pointer not in heap! Uh oh.\n"); if (GET(HDRP(bp)) != GET(FTRP(bp))) printf("Header and footer don't match! Dang...\n"); if (PREV_FREE_BLKP(NEXT_FREE_BLKP(bp)) != bp || NEXT_FREE_BLKP(PREV_FREE_BLKP(bp)) != bp) printf("Pointers do not match up! Ugh\n"); freelist_count++; } for (bp = free_listp; GET_SIZE(HDRP(bp)) > 0; bp = NEXT_BLKP(bp)) { if (!aligned(bp)) printf("Base pointer in heap is not aligned!\n"); if (GET(HDRP(bp)) != GET(FTRP(bp))) printf("Header and footer don't match! Dang...\n"); if (PREV_BLKP(NEXT_BLKP(bp)) != bp || NEXT_BLKP(PREV_BLKP(bp)) != bp) printf("Pointers do not match up! Ugh\n"); if (!GET_ALLOC(HDRP(bp))) free_count++; } if (free_count != freelist_count) printf("Free blocks in free list don't match up with heap traversal!"); }
// Return the header to the successor free block static inline uint32_t* block_succ(uint32_t* const block) { REQUIRES(block != NULL); REQUIRES(in_heap(block)); uint32_t * address = heap_listp + block[2]; ENSURES(address != NULL); ENSURES(in_heap(address)); if (address == heap_listp) return NULL; else return address; }
// Return a pointer to block of what malloc returns static inline uint32_t* block_block(uint32_t* const ptr) { REQUIRES(ptr != NULL); REQUIRES(in_heap(ptr - 1)); REQUIRES(aligned(ptr)); return ptr - 1; }
/* * malloc */ void *malloc (size_t size) { size_t a_size; size_t e_size; uint32_t *bp = NULL; if(size == 0) return NULL; if(size <= DSIZE) a_size = 2*DSIZE; else a_size = DSIZE * ((size + (DSIZE) + (DSIZE - 1)) / DSIZE); bp = find_first_fit(a_size); if(bp != NULL) { place(bp, a_size); return bp; } e_size = MAX(a_size, CHUNKSIZE); bp = extend_heap(e_size/WSIZE); if(bp != NULL) { place(bp, a_size); return bp; } if(0) in_heap(bp); return NULL; }
/* * free */ void free (void *ptr) { unsigned oldS;//store original size that ptr points to unsigned neighS;//neighbor size void *nextPtr;//used for forwards just for ease of typing if(!ptr || !in_heap(ptr)) return; ptr--; setAlloc(ptr, 0); setAlloc(ptr+(block_size(ptr)+1), 0); /* Coalesce Backwards: */ if(!is_alloc((ptr-1))){ oldS=block_size(ptr); neighS=block_size(ptr-1); ptr-=(neighS+2); createBlock(ptr, neighS+oldS+2, 0); } /* Coalesce Forwards: *independent from backwards, just use ptr */ nextPtr=ptr+block_size(ptr)+2; if(!is_alloc(nextPtr)) createBlock(ptr, block_size(nextPtr)+2, 0); }
// Return a pointer to the memory malloc should return static inline uint32_t* block_mem(uint32_t* const block) { REQUIRES(block != NULL); REQUIRES(in_heap(block)); REQUIRES(aligned(block + 1)); return block + 1; }
/* * Place the block and potentially split the block * Return: Nothing */ static void place(void *block, unsigned int awords) { REQUIRES(awords >= 2 && awords % 2 == 0); REQUIRES(block != NULL); REQUIRES(in_heap(block)); REQUIRES(in_list(block)); unsigned int cwords = block_size(block); //the size of the given freeblock block_delete(block); // delete block from the seg list ENSURES(!in_list(block)); if ((cwords - awords) >= 4) { set_size(block, awords); block_mark(block, ALLOCATED); block = block_next(block); set_size(block, cwords - awords - 2); block_mark(block, FREE); block_insert(block); ENSURES(in_list(block)); } else { set_size(block, cwords); block_mark(block, ALLOCATED); } }
/* * Requires: * None. * * Effects: * Perform a minimal check of the heap for consistency. */ void checkheap(bool verbose) { void *bp; if (verbose) printf("Heap (%p):\n", heap_listp); if (GET_SIZE(HDRP(heap_listp)) != DSIZE || !GET_ALLOC(HDRP(heap_listp))) printf("Bad prologue header\n"); checkblock(heap_listp); for (bp = heap_listp; GET_SIZE(HDRP(bp)) > 0; bp = (void *)NEXT_BLKP(bp)) { if (verbose) printblock(bp); checkblock(bp); } if (verbose) printblock(bp); if (GET_SIZE(HDRP(bp)) != 0 || !GET_ALLOC(HDRP(bp))) printf("Bad epilogue header\n"); in_heap(bp); check_coalescing(); check_free_list(); check_free_blocks(); }
// Delete the given block from the seg list static inline void block_delete(uint32_t* block) { REQUIRES(block != NULL); REQUIRES(in_heap(block)); uint32_t *pred = block_pred(block); uint32_t *succ = block_succ(block); int index = find_index(block_size(block)); if (pred == NULL && succ == NULL) { // The list has only one block seg_list[index] = NULL; } else if (pred == NULL && succ != NULL) { // This block is at the head, seg_list[index] == block set_ptr(succ, NULL, block_succ(succ)); seg_list[index] = succ; } else if (pred != NULL && succ == NULL) { // This block is at the tail set_ptr(pred, block_pred(pred), NULL); } else { // This block is the middle of somewhere set_ptr(pred, block_pred(pred), succ); set_ptr(succ, pred, block_succ(succ)); } }
static inline void set_size(uint32_t* block, size_t size){ REQUIRES(block != NULL); REQUIRES(in_heap(block)); *block = size & 0x3FFFFFFF; *(block + block_size(block)/sizeof(uint32_t*) - 1) = size & 0x3FFFFFFF; }
/* * Set the pred and succ of the given free block * Since the whole memory space is 2^32 bytes * I can compress the 8 bytes address into 4 bytes * by computing its offest to heap_listp */ static inline void set_ptr(uint32_t* const block, uint32_t* const pred_block, uint32_t* const succ_block) { REQUIRES(block != NULL); REQUIRES(in_heap(block)); unsigned int pred_offest; unsigned int succ_offest; if (pred_block == NULL) pred_offest = 0; else pred_offest = pred_block - heap_listp; if (succ_block == NULL) succ_offest = 0; else succ_offest = succ_block - heap_listp; //printf("pred_off = %d, succ_off = %d\n", pred_offest, succ_offest); set_val(block + 1 , pred_offest); set_val(block + 2 , succ_offest); ENSURES(block_pred(block) == pred_block); ENSURES(block_succ(block) == succ_block); }
// Return a pointer to the memory malloc should return static inline void* block_mem(uint64_t* block) { REQUIRES(block != NULL); REQUIRES(in_heap(block)); REQUIRES(aligned(block)); REQUIRES(aligned(block + 3)); return (void*)(block+3); }
void test_alloc_string() { int str_length; byte *before, *after; String *s; before = heap_address(); s = alloc_String(12); after = heap_address(); strcpy(s->elements, "abcdefghijkl"); str_length = sizeof_array(12, ARRAY_CHAR); ASSERT(align(str_length), (after - before)); ASSERT(12, s->length); ASSERT_TRUE(in_heap((Object *) s)); ASSERT_STR("abcdefghijkl", s->elements); ASSERT_TRUE(in_heap((Object *) s->elements)); }
/* * mm_checkheap */ void mm_checkheap(int verbose) { if (verbose) printf("Heap (%p):\n", freelist); in_heap(freelist); aligned(freelist); }
// Return the size of the given block in multiples of the word size static inline unsigned int block_size(const uint32_t* block) { REQUIRES(block != NULL); REQUIRES(in_heap(block)); //return (block[0] & 0x3FFFFFFF); return (*block)&(~0x7); }
// Mark the given block as free(1)/alloced(0) by marking the header and footer. static inline void block_mark(uint32_t* block, int free) { REQUIRES(block != NULL); REQUIRES(in_heap(block)); //unsigned int next = block_size(block) + 1; block[0] = free ? block[0] & (int) 0xBFFFFFFF : block[0] | 0x40000000; //block[next] = block[0]; }
// Return a pointer to the memory malloc should return static inline uint32_t* block_mem(uint32_t* const block) { REQUIRES(block != NULL); REQUIRES(in_heap(block)); REQUIRES(aligned(block + 1)); if (VERBOSE) printf("Heap size = %d bytes \n", (int)mem_heapsize()); return block + 1; }
// Mark the given block as free(1)/alloced(0) by marking the header and footer. static inline void block_mark(uint32_t* block, int free) { REQUIRES(block != NULL); REQUIRES(in_heap(block)); unsigned int size = block_size(block); PUT(block, PACK(size, free)); PUT((block + (size/WSIZE) - 1), PACK(size, free)); }
// Set the size of the given block in multiples of 4 bytes static inline void set_size(uint32_t* const block, unsigned int size) { REQUIRES(block != NULL); REQUIRES(in_heap(block)); REQUIRES(size % 2 == 0); set_val(block, size); }
static int coalesce(void* block, size_t* size){ REQUIRES(block != NULL); REQUIRES(in_heap(block)); //uint64_t* left_block; void* right_block; size_t new_size; int index; void* next; void* prev; *size = block_size(block); new_size = (*size) * 2; index = get_free_list_index(*size); if(new_size > MAX_SIZE) return index; right_block = ((uint64_t*)block)+(block_size(block)/sizeof(uint64_t*)); // if(in_heap(left_block) && block_free(left_block)){ // if(block_size(left_block) == size){ // set_size(left_block, size*2); // add_block_to_list(get_free_list_index(size*2), left_block); // } // } if(in_heap(right_block) && block_free((uint32_t*)right_block)){ if(block_size(right_block) == new_size/2){ next = block_next(right_block); prev = block_prev(right_block); if(free_lists[index] == right_block) free_lists[index] = next; if(prev != NULL) set_next_pointer(prev, next); if(next != NULL) set_prev_pointer(next, prev); set_size(block, new_size); *size = new_size; index++; } } return index; }
/* * Merge block with adjacent free blocks * Return: the pointer to the new free block */ static void *coalesce(void *block) { REQUIRES(block != NULL); REQUIRES(in_heap(block)); uint32_t *prev_block = block_prev(block); uint32_t *next_block = block_next(block); int prev_free = block_free(prev_block); int next_free = block_free(next_block); unsigned int words = block_size(block); if (prev_free && next_free) { // Case 4, both free block_delete(prev_block); block_delete(next_block); words += block_size(prev_block) + block_size(next_block) + 4; set_size(prev_block, words); block_mark(prev_block, FREE); block = (void *)prev_block; block_insert(block); ENSURES(in_list(block)); } else if (!prev_free && next_free) { // Case 2, next if free block_delete(next_block); words += block_size(next_block) + 2; set_size(block, words); block_mark(block, FREE); block_insert(block); ENSURES(in_list(block)); } else if (prev_free && !next_free) { // Case 3, prev is free block_delete(prev_block); words += block_size(prev_block) + 2; set_size(prev_block, words); block_mark(prev_block, FREE); block = (void *)prev_block; block_insert(block); ENSURES(in_list(block)); } else { // Case 1, both unfree block_insert(block); ENSURES(in_list(block)); return block; } return block; }
// set header and footer static void *set_free_block(void *bp,size_t size,uint32_t alloc){ REQUIRES(in_heap(bp)); PUT((uint32_t *)bp,PACK((uint32_t)size,alloc)); PUT((uint32_t *)bp+1,0);//pred addr PUT((uint32_t *)bp+2,0);//succ addr PUT(FTRP1(bp), PACK((uint32_t)size, alloc)); return bp; }
static void add_block_to_list(int index, void* block){ REQUIRES(0 <= index && index <= NUM_FREE_LISTS); REQUIRES(block != NULL); REQUIRES(in_heap(block)); set_prev_pointer(block, NULL); set_next_pointer(block, free_lists[index]); if(free_lists[index] != NULL) set_prev_pointer(free_lists[index], block); free_lists[index] = block; }
// Insert the given free block into seg list according to its size static inline void block_insert(uint32_t* block) { REQUIRES(block != NULL); REQUIRES(in_heap(block)); int index = find_index(block_size(block)); //printf("index = %d, size = %d\n", index, block_size(block)); uint32_t *old_block = seg_list[index]; if (old_block == NULL) { // this list is empty set_ptr(block, NULL, NULL); seg_list[index] = block; } else { // this list is not empty ENSURES(block_pred(old_block) == NULL); ENSURES(block_succ(old_block) == NULL || in_heap(block_succ(old_block))); set_ptr(old_block, block, block_succ(old_block)); set_ptr(block, NULL, old_block); seg_list[index] = block; } ENSURES(in_list(block)); }
void test_alloc_user() { byte *before, *after; User *u; before = heap_address(); u = (User *) alloc(&User_type); after = heap_address(); ASSERT(align(User_type.size), (after - before)); ASSERT_TRUE(in_heap((Object *) u)); }
/* * free */ void free(void *ptr) { dbg_printf("=== FREE : 0x%lx\n",(size_t)ptr); #if DEBUG if (NEXT_BLKP(ptr)) { if (!GET_PREV_ALLOC(GET_HEADER(NEXT_BLKP(ptr)))) { dbg_printf("0x%lx Fail to inform next block when malloc, or next block fail to update\n", (size_t)ptr); exit(3); } } #endif if(!ptr) return; /* Debug */ if(!in_heap(ptr)) { dbg_printf("ptr is not in heap!\n"); mm_checkheap(63); exit(1); } if (!aligned(ptr)) { dbg_printf("ptr is not aligned!\n"); mm_checkheap(63); exit(1); } size_t bsize = GET_SIZE(GET_HEADER(ptr)); size_t flag = GET_PREV_ALLOC(GET_HEADER(ptr)) ? 0x2 : 0x0; PUT(GET_HEADER(ptr), PACK(bsize, flag)); PUT(GET_FOOTER(ptr), PACK(bsize, flag)); /* Inform the next block that this block is freed */ char *nextbp = NEXT_BLKP(ptr); if (nextbp) { flag = GET(GET_HEADER(nextbp)); flag &= ~0x2; PUT(GET_HEADER(nextbp), flag); /* Only put footer when next block is free */ if (!GET_ALLOC(GET_HEADER(nextbp))) { PUT(GET_FOOTER(nextbp), flag); } } coalesce(ptr); mm_checkheap(CHECK_HEAP); }
static void *find_fit(size_t asize){ void *bp; if (free_list==base) return NULL; for (bp=free_list;get_succ_offset(bp)!=0;bp=succ_blkp(bp)){ if (GET_SIZE(bp)>=asize){ in_heap(bp); return bp; } } return NULL; }
/* addfreeblock*/ static void *add_free_block(void *bp){ REQUIRES(in_heap(bp)); set_succ(bp,get_offset(free_list)); set_pred(bp,0); if (get_offset(free_list)!=0) set_pred(free_list,get_offset(bp)); //set new list header free_list=bp; return bp; }
void MultiTimeout::add_timeout_at(int64 key, double timeout) { LOG(DEBUG) << "Add timeout for " << key << " in " << timeout - Time::now(); auto item = items_.emplace(key); auto heap_node = static_cast<HeapNode *>(const_cast<Item *>(&*item.first)); if (heap_node->in_heap()) { CHECK(!item.second); } else { CHECK(item.second); timeout_queue_.insert(timeout, heap_node); if (heap_node->is_top()) { update_timeout(); } } }
void MultiTimeout::cancel_timeout(int64 key) { LOG(DEBUG) << "Cancel timeout for " << key; auto item = items_.find(Item(key)); if (item != items_.end()) { auto heap_node = static_cast<HeapNode *>(const_cast<Item *>(&*item)); CHECK(heap_node->in_heap()); bool need_update_timeout = heap_node->is_top(); timeout_queue_.erase(heap_node); items_.erase(item); if (need_update_timeout) { update_timeout(); } } }