/* memmap_free_t* merge_block(memmap_free_t* mmap_left, memmap_free_t* mmap_right) Merges two contiguous block of free memory. */ memmap_free_t* merge_block(memmap_free_t* mmap_left, memmap_free_t* mmap_right) { memmap_t* mmap_left_alloc = (memmap_t*) mmap_left; memmap_t* mmap_right_alloc = (memmap_t*) mmap_right; if(is_last_in_memory(mmap_right_alloc)) { set_next_block(mmap_left_alloc, mmap_left_alloc); } else { set_next_block(mmap_left_alloc, get_next_block(mmap_right_alloc)); set_prev_block(get_next_block(mmap_right_alloc), mmap_left_alloc); } #ifdef DEBUG_MEMORY printf("Left: %d, right: %d ,", get_block_size(mmap_left_alloc), get_block_size(mmap_right_alloc)); #endif remove_free_block(mmap_right); remove_free_block(mmap_left); set_block_size(mmap_left_alloc, get_block_size(mmap_left_alloc) + get_block_size(mmap_right_alloc)); #ifdef DEBUG_MEMORY printf("new left: %d\n", get_block_size(mmap_left_alloc)); #endif return mmap_left; }
static void place(hblock *bp, size_t newsize) { size_t csize = GET_SIZE(bp->header); if ((csize - newsize) >= 24) { bp->header = newsize | 0x1; bp->footer = bp->header; remove_free_block(bp); bp = (hblock *) NEXT_BLKP(bp); bp->header = (csize-newsize) | 0x0; bp->footer = bp->header; coalesce(bp); } else { bp->header = csize | 0x1; bp->footer = bp->header; remove_free_block(bp); } /* Set the allocated bit of the header and footer */ //bp->header |= 0x1; //bp->footer = bp->header; /* Set up the link for the free list */ //remove_free_block(bp); return; }
/********************************************************** * coalesce * Covers the 4 cases discussed in the text: * - both neighbours are allocated * - the next block is available for coalescing * - the previous block is available for coalescing * - both neighbours are available for coalescing **********************************************************/ void *coalesce(void *bp) { //printf("IN COALESCE\n"); //printf("coalescing block ptr %p\n",bp); size_t prev_alloc = GET_ALLOC(FTRP(PREV_BLKP(bp))); size_t next_alloc = GET_ALLOC(HDRP(NEXT_BLKP(bp))); size_t size = GET_SIZE(HDRP(bp)); //printf("sizeof size_t %08p\n",sizeof(size_t)); if (prev_alloc && next_alloc) { /* Case 1 */ //printf("case 1\n"); add_to_free_list(bp); //add to the free list //print_ptr(bp); return bp; } else if (prev_alloc && !next_alloc) { /* Case 2 */ //printf("case 2\n"); size += GET_SIZE(HDRP(NEXT_BLKP(bp))); remove_free_block(NEXT_BLKP(bp)); //remove the free block from the free list PUT(HDRP(bp), PACK(size, 0)); PUT(FTRP(bp), PACK(size, 0)); add_to_free_list(bp); return (bp); } else if (!prev_alloc && next_alloc) { /* Case 3 */ //printf("case 3\n"); size += GET_SIZE(HDRP(PREV_BLKP(bp))); remove_free_block(PREV_BLKP(bp)); PUT(FTRP(bp), PACK(size, 0)); PUT(HDRP(PREV_BLKP(bp)), PACK(size, 0)); add_to_free_list(PREV_BLKP(bp)); //print_ptr(PREV_BLKP(bp)); //print_ptr(bp); return (PREV_BLKP(bp)); } else { /* Case 4 */ //printf("case 4\n"); size += GET_SIZE(HDRP(PREV_BLKP(bp)))+GET_SIZE(FTRP(NEXT_BLKP(bp))); remove_free_block(PREV_BLKP(bp)); remove_free_block(NEXT_BLKP(bp)); PUT(HDRP(PREV_BLKP(bp)), PACK(size,0)); PUT(FTRP(NEXT_BLKP(bp)), PACK(size,0)); add_to_free_list(PREV_BLKP(bp)); //print_ptr(bp); return (PREV_BLKP(bp)); } }
/* * place - Place block of asize bytes at start of free block bp * and split if remainder would be at least minimum block size * * given a free block, removes free block from list and updates all relevant pointers * */ static void place(void* bp, size_t asize) { size_t old_size = GET_SIZE(HDRP(bp)); size_t prev_alloc = GET_PREV_ALLOC(HDRP(bp)); size_t temp_value; dbg1("[IN ] : place()\n"); /* remove free block from free list */ remove_free_block(bp); /* check to see if block can be split up */ dbg1("old_size=%ld, asize=%ld, compare=%d\n", old_size, asize, (int) OVERHEAD+2*DSIZE); if (old_size - asize >= OVERHEAD + 2*DSIZE) { /* block can be split up */ PUT(HDRP(bp), PACK(asize, prev_alloc | 0x1)); PUT(HDRP(NEXT_BLKP(bp)), PACK( old_size - asize, 0x2 )); PUT(FTRP(NEXT_BLKP(bp)), PACK( old_size - asize, 0x2 )); insert_free_block(NEXT_BLKP(bp)); } else { /* just use entire block */ PUT(HDRP(bp), PACK(old_size, prev_alloc | 0x1)); temp_value = GET(HDRP(NEXT_BLKP(bp))) | 0x2; PUT(HDRP(NEXT_BLKP(bp)), temp_value); } dbg1("[OUT] : place()\n"); }
/* Free the block whose first page (aka block leader) is specified * by "page_idx". return 1 on success and 0 otherwise. */ int free_block(page_idx_t page_idx) { (void)remove_alloc_block(page_idx); lm_page_t* pi = alloc_info->page_info; lm_page_t* page = pi + page_idx; int order = page->order; ASSERT (find_block(page_idx, order, NULL) == 0); /* Consolidate adjacent buddies */ int page_num = alloc_info->page_num; page_id_t page_id = page_idx_to_id(page_idx); int min_page_id = alloc_info->idx_2_id_adj; while (1) { page_id_t buddy_id = page_id ^ (1<<order); if (buddy_id < min_page_id) break; page_idx_t buddy_idx = page_id_to_idx(buddy_id); if (buddy_idx >= page_num || pi[buddy_idx].order != order || !is_page_leader(pi + buddy_idx) || is_allocated_blk(pi + buddy_idx)) { break; } remove_free_block(buddy_idx, order, 0); reset_page_leader(alloc_info->page_info + buddy_idx); page_id = page_id < buddy_id ? page_id : buddy_id; order++; } add_free_block(page_id_to_idx(page_id), order); return 1; }
/********************************************************** * coalesce * Covers the 4 cases discussed in the text: * - both neighbours are allocated * - the next block is available for coalescing * - the previous block is available for coalescing * - both neighbours are available for coalescing **********************************************************/ void *coalesce(void *bp) { logg(4, "============ coalesce() starts =============="); logg(1, "coalesce() called with bp: %p; Previous block: %p header: %zx; Next block: %p header: %zx", bp, PREV_BLKP(bp), GET(HDRP(PREV_BLKP(bp))), NEXT_BLKP(bp), GET(HDRP(NEXT_BLKP(bp)))); size_t prev_alloc = GET_ALLOC(FTRP(PREV_BLKP(bp))); size_t next_alloc = GET_ALLOC(HDRP(NEXT_BLKP(bp))); size_t size = GET_SIZE(HDRP(bp)); if (prev_alloc && next_alloc) { /* Case 1 */ logg(2, "Case 1: Both prev and next blocks are allocated. NO coalescing."); } else if (prev_alloc && !next_alloc) { /* Case 2 */ logg(2, "Case2: Next block is free."); size += GET_SIZE(HDRP(NEXT_BLKP(bp))); remove_free_block(NEXT_BLKP(bp)); PUT(HDRP(bp), PACK(size, 0)); PUT(FTRP(bp), PACK(size, 0)); } else if (!prev_alloc && next_alloc) { /* Case 3 */ logg(2, "Case3: Prev block is free."); size += GET_SIZE(HDRP(PREV_BLKP(bp))); remove_free_block(PREV_BLKP(bp)); bp = PREV_BLKP(bp); // move bp one block ahead PUT(HDRP(bp), PACK(size, 0)); PUT(FTRP(bp), PACK(size, 0)); } else { /* Case 4 */ logg(2, "Case4: Both blocks are free."); size += GET_SIZE(HDRP(PREV_BLKP(bp))) + GET_SIZE(HDRP(NEXT_BLKP(bp))) ; remove_free_block(NEXT_BLKP(bp)); remove_free_block(PREV_BLKP(bp)); bp = PREV_BLKP(bp); PUT(HDRP(bp), PACK(size,0)); PUT(FTRP(bp), PACK(size,0)); } // Add the bp block to the beginning of free list of corresponding size. add_free_block(bp); logg(4, "============ coalesce() ends =============="); return bp; }
static int locate_group_section(struct pic32_section *s, struct memory_region_struct *region) { struct pic32_memory *b; bfd_vma len = group_section_size(s); bfd_vma addr = s->sec->lma; int result = 0; /* DEBUG */ if (pic32_debug) printf(" group section \"%s\", total size = %lx\n", s->sec->name, len); /* look for tricky user error */ if (PIC32_IS_ABSOLUTE_ATTR(s->sec) && ACROSS_REGION(addr, len, region)) einfo(_(" Link Warning: absolute section \'%s\' crosses" " the boundary of region %s.\n"), s->sec->name, region->name_list.name); if (len == 0) update_group_section_info(0,s,region); /* trivial case */ else if (PIC32_IS_ABSOLUTE_ATTR(s->sec) && OUTSIDE_REGION(addr, len, region)) { update_group_section_info(addr, s, region); /* falls outside region */ } else { /* locate using free_blocks list */ b = select_free_block(s, len); if (b) { addr = b->addr + b->offset; update_group_section_info(addr,s,region); create_remainder_blocks(free_blocks,b,len); remove_free_block(b); } else { if (locate_options != NO_LOCATE_OPTION) { if (pic32_debug) printf(" \"%s\" location declined\n", s->sec->name); return 0; } result |= 1; } } if (pic32_debug) printf(" removing group from allocation list\n"); pic32_remove_group_from_section_list(alloc_section_list); return result; } /* locate_group_section() */
/********************************************************** * place * Mark the block as allocated. * Also create a new free block of the size difference if possible. **********************************************************/ void place(void* bp, size_t asize) { remove_free_block(bp); /* Get the current block size */ size_t bsize = GET_SIZE(HDRP(bp)); // Create a block of the size difference and insert it into the free list. if (bsize - asize > 8*DSIZE) { PUT(HDRP(bp), PACK(asize, 1)); PUT(FTRP(bp), PACK(asize, 1)); PUT(HDRP(NEXT_BLKP(bp)), PACK(bsize-asize, 0)); PUT(FTRP(NEXT_BLKP(bp)), PACK(bsize-asize, 0)); add_free_block(NEXT_BLKP(bp)); } else { PUT(HDRP(bp), PACK(bsize, 1)); PUT(FTRP(bp), PACK(bsize, 1)); } }
/********************************************************** * mm_malloc * Allocate a block of size bytes. * The type of search is determined by find_fit * The decision of splitting the block, or not is determined * in place(..) * If no block satisfies the request, the heap is extended **********************************************************/ void *mm_malloc(size_t size) { //mm_check(); //print_seg(0); // printf("IN MALLOC\n"); size_t asize; /* adjusted block size */ size_t extendsize; /* amount to extend heap if no fit */ char * bp; /* Ignore spurious requests */ if (size == 0) return NULL; /* Adjust block size to include overhead and alignment reqs. */ if (size <= DSIZE) asize = 2 * DSIZE; else asize = DSIZE * ((size + (DSIZE) + (DSIZE-1))/ DSIZE); /* Search the free list for a fit */ if ((bp = find_segregated_best_fit(asize)) != NULL) { //printf("free size found, bp is %p\n",bp); remove_free_block(bp); place(bp, asize); return bp; }; /* No fit found. Get more memory and place the block */ extendsize = MAX(asize, CHUNKSIZE); if ((bp = extend_heap(extendsize/WSIZE)) == NULL) { return NULL; } place(bp, asize); return bp; }
static void *coalesce(void *bp) { dbg_printf("=== Coalesce bp = 0x%lx\n", (size_t)bp); void *prevbp = PREV_BLKP(bp); void *nextbp = NEXT_BLKP(bp); /*ONLY use the former alloc flag */ size_t prev_alloc = GET_PREV_ALLOC(GET_HEADER(bp)); /*GET_ALLOC(GET_FOOTER(prevbp));*/ size_t next_alloc = GET_ALLOC(GET_HEADER(nextbp)); size_t bsize = GET_SIZE(GET_HEADER(bp)); size_t flag = 0; int class_idx = 0; /* case 1: make newly freed block to be root */ if (prev_alloc && next_alloc) { dbg_printf("Coalesce Case 1\n"); insert_first(bp); return bp; } /* case 3: next block is free */ else if (prev_alloc && !next_alloc) { dbg_printf("Coalesce Case 3\n"); class_idx = get_class_idx_by_size(GET_SIZE(GET_HEADER(nextbp))); remove_free_block(nextbp, class_idx); /* Telling coalesced free block about if bp's previous allocated */ flag = GET_PREV_ALLOC(GET_HEADER(bp)) ? 0x2 : 0x0; bsize += GET_SIZE(GET_HEADER(nextbp)); PUT(GET_HEADER(bp), PACK(bsize, flag)); PUT(GET_FOOTER(bp), PACK(bsize, flag)); insert_first(bp); return bp; } /* case 2: prev block is free */ else if (!prev_alloc && next_alloc) { dbg_printf("Coalesce Case 2\n"); class_idx = get_class_idx_by_size(GET_SIZE(GET_HEADER(prevbp))); dbg_printf("class_idx = %d, class_address = 0x%lx\n", class_idx, (size_t)GET_CLASS(class_idx)); remove_free_block(prevbp, class_idx); /* Telling coalesced free block about if bp's previous's previous allocated */ flag = GET_PREV_ALLOC(GET_HEADER(prevbp)) ? 0x2 : 0x0; if (flag == 0) { printf("Implies fail coalese: 0x%lx with former\n", (size_t)prevbp); exit(2); } bsize += GET_SIZE(GET_HEADER(prevbp)); PUT(GET_HEADER(prevbp), PACK(bsize, flag)); PUT(GET_FOOTER(prevbp), PACK(bsize, flag)); insert_first(prevbp); return prevbp; } /* case 4: both blocks are free */ else { dbg_printf("Coalesce Case 4\n"); class_idx = get_class_idx_by_size(GET_SIZE(GET_HEADER(nextbp))); remove_free_block(nextbp, class_idx); class_idx = get_class_idx_by_size(GET_SIZE(GET_HEADER(prevbp))); remove_free_block(prevbp, class_idx); /* Telling coalesced free block about if bp's previous's previous allocated */ flag = GET_PREV_ALLOC(GET_HEADER(prevbp)) ? 0x2 : 0x0; if (flag == 0) { printf("Implies fail coalese: 0x%lx with former\n", (size_t)prevbp); exit(2); } bsize += GET_SIZE(GET_HEADER(nextbp)); bsize += GET_SIZE(GET_FOOTER(prevbp)); PUT(GET_HEADER(prevbp), PACK(bsize, flag)); PUT(GET_FOOTER(nextbp), PACK(bsize, flag)); insert_first(prevbp); return prevbp; } dbg_printf("Unable to coalesce!\n"); return NULL; }
/* Place an ADJUSTED sized block in heap */ static void place(void *bp, size_t asize) { #if DEBUG if (NEXT_BLKP(bp)) { if (GET_PREV_ALLOC(GET_HEADER(NEXT_BLKP(bp)))) { dbg_printf("0x%lx: Fail to inform next block when free\n", (size_t)bp); exit(2); } } #endif dbg_printf("=== Place, bp = 0x%lx, adjusted size = %ld \n", (size_t)bp, asize); /* block free size */ size_t csize = GET_SIZE(GET_HEADER(bp)); char *nextbp = NULL; int class_idx = 0; size_t flag = 0; /* Split, say, minimum block size set to 1 WSIZE = 8 byte */ if ((csize - asize) >= (4 * WSIZE)) { class_idx = get_class_idx_by_size(GET_SIZE(GET_HEADER(bp))); /* Include previous block's information */ flag = GET_PREV_ALLOC(GET_HEADER(bp)) ? 0x3 : 0x1; PUT(GET_HEADER(bp), PACK(asize, flag)); PUT(GET_FOOTER(bp), PACK(asize, flag)); nextbp = NEXT_BLKP(bp); PUT(GET_HEADER(nextbp), PACK((csize - asize), 0)); PUT(GET_FOOTER(nextbp), PACK((csize - asize), 0)); /* Inform the next block that this block is allocated */ flag = GET(GET_HEADER(nextbp)); flag |= 0x2; PUT(GET_HEADER(nextbp), flag); PUT(GET_FOOTER(nextbp), flag); split_free_block(bp, nextbp); remove_free_block(bp, class_idx); remove_free_block(nextbp, class_idx); insert_first(nextbp); mm_checkheap(CHECK_HEAP); } else { /* Include previous block's information */ flag = GET_PREV_ALLOC(GET_HEADER(bp)) ? 0x3 : 0x1; PUT(GET_HEADER(bp), PACK(csize, flag)); PUT(GET_FOOTER(bp), PACK(csize, flag)); /* Inform the next block that this block is allocated */ if ((size_t)bp == 0x800004980) { dbg_printf("bp size = %ld\n",GET_SIZE(GET_HEADER(bp))); dbg_printf("NEXT_BLKP(bp); 0x%lx\n",(size_t)NEXT_BLKP(bp)); } nextbp = NEXT_BLKP(bp); 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); } } remove_free_block(bp, get_class_idx_by_size(csize)); } }
/* * coalesce - boundary tag coalescing. return ptr to coalesced block * */ static void* coalesce(void* bp) { size_t prev_alloc = GET_PREV_ALLOC(HDRP(bp)); size_t next_alloc = GET_ALLOC(HDRP(NEXT_BLKP(bp))); size_t size = GET_SIZE(HDRP(bp)); dbg1("[IN ] : coalesce()\n"); switch (prev_alloc | next_alloc) { case 3: /* neither of the adjacent blocks are free */ insert_free_block(bp); dbg1("[OUT] : coalesce() : neither of the adjacent blocks are free.\n"); return bp; case 2: /* next block is free */ size += GET_SIZE(HDRP(NEXT_BLKP(bp))); /* remove next block from free list */ remove_free_block(NEXT_BLKP(bp)); /* update header and footer pointers */ PUT(HDRP(bp), PACK(size, prev_alloc)); PUT(FTRP(bp), PACK(size, prev_alloc)); /* insert new merged block into free list */ insert_free_block(bp); dbg1("[OUT] : coalesce() : next block is free - merged \n"); return(bp); case 1: /* prev block is free */ size += GET_SIZE(HDRP(PREV_BLKP(bp))); /* remove this block from free list */ remove_free_block(PREV_BLKP(bp)); /* update header and footer pointers */ prev_alloc = GET_PREV_ALLOC(HDRP(PREV_BLKP(bp))); PUT(FTRP(bp), PACK(size, prev_alloc)); PUT(HDRP(PREV_BLKP(bp)), PACK(size, prev_alloc)); /* insert new merged block into free list */ insert_free_block(PREV_BLKP(bp)); dbg1("[OUT] : coalesce() : previous block is free - merged \n"); return(PREV_BLKP(bp)); default: /* both previous and next blocks are free */ size += GET_SIZE(HDRP(PREV_BLKP(bp))) + GET_SIZE(FTRP(NEXT_BLKP(bp))); /* remove next block from free list */ remove_free_block(NEXT_BLKP(bp)); /* remove this block from free list */ remove_free_block(PREV_BLKP(bp)); /* update header and footer pointers */ prev_alloc = GET_PREV_ALLOC(HDRP(PREV_BLKP(bp))); PUT(HDRP(PREV_BLKP(bp)), PACK(size, prev_alloc)); PUT(FTRP(NEXT_BLKP(bp)), PACK(size, prev_alloc)); /* insert new merged block into free list */ insert_free_block(PREV_BLKP(bp)); dbg1("[OUT] : coalesce() : both previous and next blocks are free - merged \n"); return(PREV_BLKP(bp)); } }
/* To extend the given exiting allocated block such that it can accommodate * at least new_sz bytes. */ int extend_alloc_block(page_idx_t block_idx, size_t new_sz) { rb_tree_t* rbt = &alloc_info->alloc_blks; intptr_t alloc_sz; int res = rbt_search(rbt, block_idx, &alloc_sz); #ifdef DEBUG ASSERT(res); #else (void)res; #endif int page_sz = alloc_info->page_size; int page_sz_log2 = alloc_info->page_size_log2; int min_page_num = (new_sz + page_sz - 1) >> page_sz_log2; page_id_t blk_id = page_idx_to_id(block_idx); int order = alloc_info->page_info[block_idx].order; /* step 1: The in-place block extension is done by merging its *following* * free buddy to a form bigger block. The extension process repeats until * we find a block bigger enough to accommodate the <new_sz> bytes. */ int succ = 0; int ord; for (ord = order; ord <= alloc_info->max_order; ord++) { if (min_page_num <= (1 << ord)) { succ = 1; break; } page_id_t buddy_id = blk_id ^ (1 << ord); if (buddy_id < blk_id) { /* The buddy block must reside at higher address. */ break; } int buddy_idx = page_id_to_idx(buddy_id); if (!rbt_search(&alloc_info->free_blks[ord], buddy_idx, NULL)) { /* bail out if the buddy is not available */ break; } } /* This function is not supposed to shrink the existing block; therefore, * if the existing block is big enough to accommodate allocation request, * it need to return 0 to inform the caller that something fishy is * happening. */ if (!succ || ord == order) return 0; /* Step 2: The previous step is merely a 'dry-run' of extension. This * step is to perform real transformation. */ int t; for (t = order; t < ord; t++) { page_id_t buddy_id = blk_id ^ (1 << t); int buddy_idx = page_id_to_idx(buddy_id); remove_free_block(buddy_idx, t, 0); reset_page_leader(alloc_info->page_info + buddy_idx); } migrade_alloc_block(block_idx, order, ord, new_sz); return 1; }