void free(void *address) { struct heapnode *node = (struct heapnode *) ((uint32_t) address - BUDDY_HEADER_SIZE); acquire(&user_buddy.semaphore); buddy_merge(node, &user_buddy); release(&user_buddy.semaphore); }
void kfree(void *address) { struct heapnode *node = (struct heapnode *) ((uint8_t *) address - MM_HEADER_SIZE); acquire(&kernel_buddy.mutex); buddy_merge(node, &kernel_buddy); release(&kernel_buddy.mutex); }
void buddy_merge(struct heapnode *node, struct buddy *buddy) { struct heapnode *buddy_node = (struct heapnode *) ((uint32_t) node ^ (1 << node->order)); /* Note: this is not necessarily free */ struct heapnode *curr_node = buddy->list[node->order]; struct heapnode *prev_node = NULL; if (node->order >= buddy->max_order) { return; } /* Look for node and buddy */ uint8_t found = 0; struct heapnode *node_curr_node = NULL; struct heapnode *node_prev_node = NULL; struct heapnode *buddy_curr_node = NULL; struct heapnode *buddy_prev_node = NULL; while (found < 2 && curr_node != NULL) { if (curr_node == node) { node_curr_node = curr_node; node_prev_node = prev_node; found += 1; } else if (curr_node == buddy_node) { buddy_curr_node = curr_node; buddy_prev_node = prev_node; found += 1; } prev_node = curr_node; curr_node = curr_node->next; } /* Buddy not free */ if (buddy_curr_node == NULL) { if (node_curr_node == NULL) { node->next = buddy->list[node->order]; buddy->list[node->order] = node; } return; } else { /* Buddy free */ /* Remove from list */ if (buddy_prev_node == NULL) { buddy->list[node->order] = buddy_curr_node->next; } else { buddy_prev_node->next = buddy_curr_node->next; } /* Remove node if found */ if (node_curr_node != NULL) { /* Remove from list */ if (node_prev_node == NULL) { buddy->list[node->order] = node_curr_node->next; } else { node_prev_node->next = node_curr_node->next; } } /* Set parent node as the less of the two buddies */ node = node < buddy_curr_node ? node : buddy_curr_node; node->order += 1; node->next = buddy->list[node->order]; buddy->list[node->order] = node; /* Recurse */ buddy_merge(node, buddy); } }
void buddy_merge(struct heapnode *node, struct buddy *buddy) { if (node->header.magic != MM_MAGIC) { fprintf(stderr, "OOPS: mm: attempted to merge invalid node 0x%x\r\n", node); return; } uint8_t order = node->header.order; /* There is only one node of maximum size */ if (order == buddy->max_order) { buddy->list[buddy->max_order] = node; node->next = NULL; return; } /* Our buddy node covers the other half of this order of memory, * thus it will have the order bit in the opposite state of ours. * Note: this is not necessarily free */ struct heapnode *buddy_node = (struct heapnode *) ((uintptr_t) node ^ (1 << order)); struct heapnode *curr_node = buddy->list[order]; struct heapnode *prev_node = NULL; /* Look for node and buddy */ uint8_t found = 0; struct heapnode *node_curr_node = NULL; struct heapnode *node_prev_node = NULL; struct heapnode *buddy_curr_node = NULL; struct heapnode *buddy_prev_node = NULL; while (found < 2 && curr_node != NULL) { if (curr_node == node) { node_curr_node = curr_node; node_prev_node = prev_node; found += 1; } else if (curr_node == buddy_node) { buddy_curr_node = curr_node; buddy_prev_node = prev_node; found += 1; } prev_node = curr_node; curr_node = curr_node->next; } /* Buddy not free */ if (buddy_curr_node == NULL) { /* If node already in list, leave it, * otherwise add it */ if (node_curr_node == NULL) { node->next = buddy->list[order]; buddy->list[order] = node; } return; } else { /* Buddy free */ if (buddy_node->header.order != order) { panic_print("mm: node->header.order != buddy_node->header.order, " "node: 0x%x node->header.order: %d buddy_node: 0x%x, " "buddy_node->header.order: %d", node, node->header.order, buddy_node, buddy_node->header.order); } /* Remove buddy from list */ if (buddy_prev_node == NULL) { buddy->list[order] = buddy_curr_node->next; } else { buddy_prev_node->next = buddy_curr_node->next; } /* Remove node if found */ if (node_curr_node != NULL) { /* Remove node from list */ if (node_prev_node == NULL) { buddy->list[order] = node_curr_node->next; } else { node_prev_node->next = node_curr_node->next; } } /* Set parent node as the less of the two buddies */ node = node < buddy_curr_node ? node : buddy_curr_node; /* Merge the nodes simply by increasing the order * of the smaller node. */ uint8_t new_order = order + 1; node->header.order = new_order; /* Put on higher order list */ node->next = buddy->list[new_order]; buddy->list[new_order] = node; /* Recurse */ buddy_merge(node, buddy); } }
void* buddy_alloc(size_t size) { void* allocated_block = NULL; // The object to return void* allocated_block_from_merge = NULL; item* allocated_block_item = NULL; void* available_block = NULL; item* available_block_item = NULL; int next_power_of_2 = 0; int calculated_level = 0; int j = 0; void *list = NULL; item *new_head; printf("Allocation request for %d\n", (int)size); //Calculate the power of 2 big enough to hold 'size' next_power_of_2 = get_next_power_of_2(size); calculated_level = get_level(next_power_of_2); d_printf("next_power_of_2 %d\n", next_power_of_2); d_printf("calculated_level %d\n", calculated_level); assert(calculated_level < freelist_object->max_level); // Check the free-list if there are any free blocks for that level in the freelist array // If not, find a block in the upper level. // Split the block // Assign the block to the return object. for (j = calculated_level; j <= freelist_object->max_level; j++) { list = freelist_object->freelist[j]; if (list == NULL) continue; available_block_item = (item *)list; /* Detach it from it's current position in the free list array */ new_head = available_block_item->next; if(new_head == NULL) freelist_object->freelist[j] = NULL; else freelist_object->freelist[j] = (void*)new_head; if(available_block_item == NULL) { printf("Memory full. Try evicting"); return NULL; } d_printf("Big enough block %p found at level %d\n", available_block_item, j); /* Trim if a higher order block than necessary was allocated */ allocated_block_item = available_block_item; while (j > calculated_level) { /* Perform the splitting iteratively */ // , (int)(((item *)allocated_block)->size) // d_printf("Size : %ld\n", allocated_block_item->size); d_printf("Splitting %p at level %d ", available_block_item, j); --j; available_block_item = available_block_item + (1UL << j); available_block_item->size = (1UL << j); allocated_block_item->size = (1UL << j); d_printf("into %p and %p\n", allocated_block_item, available_block_item); /* Check if there is already free block of that level */ /* If no, make this the first one */ if(freelist_object->freelist[j] == NULL) freelist_object->freelist[j] = (void*)allocated_block_item; /* Else get the first one, link it to this block and make the block the first in that level */ else { available_block_item->next = (item*)freelist_object->freelist[j]; freelist_object->freelist[j] = (void*)allocated_block_item; } allocated_block_item = available_block_item; } d_printf("Block %p alloted out of the level %d\n", allocated_block_item, j); // Return the object if it does not cause internal fragmentatation if((1UL << calculated_level) - size == 0) { d_printf("No internal fragmentatation involved with this request size\n"); allocated_block_item->in_use = true; allocated_block = (void*)allocated_block_item; return allocated_block; } //else invoke the buddy_exact_alloc method allocated_block = (void*)allocated_block_item; return buddy_exact_alloc(&allocated_block, size); } printf("No blocks found in higher levels of the free list. Exploring the lower levels and checking if something can be merged\n"); available_block = (void*)available_block_item; allocated_block_from_merge = buddy_merge(size); if(allocated_block_from_merge == NULL) { printf("Memory full. Try evicting"); return NULL; } d_printf("Block %p alloted out of the level %d\n", (item *)allocated_block_from_merge, get_level(((item *)allocated_block_from_merge)->size)); return allocated_block_from_merge; }