#include #include #include /* ------------------------------------------------------------------------------------------------------------------ */ /* */ C_STATIC_FORCE_INLINE c_bool_t is_power_of_two(c_size_t x) { return (x & (x-1)) == 0; } C_STATIC_FORCE_INLINE c_BuddyBlock_t* buddy_block_next(c_BuddyBlock_t* block) { return (c_BuddyBlock_t*)((uint8_t*)block + block->size); } static c_BuddyBlock_t *buddy_block_split(c_BuddyBlock_t *block, const int size) { if (block != NULL && size != 0) { // 當目標大小小於當前區塊時,進行對半裂變 while (size < block->size) { int sz = block->size >> 1; block->size = sz; // 裂變出的右半邊(Right Buddy)設為空閒 c_BuddyBlock_t* right_buddy = buddy_block_next(block); right_buddy->size = sz; right_buddy->is_free = C_TRUE; // 經典夥伴系統優先分配左半邊(Left Buddy),因此 block 指針保持在左側繼續循環 } if (size <= block->size) { return block; } } return NULL; } static c_BuddyBlock_t *buddy_block_find_best(c_BuddyBlock_t *head, c_BuddyBlock_t *tail, int size) { c_BuddyBlock_t *best_block = NULL; c_BuddyBlock_t *curr = head; while (curr < tail) { if (curr->is_free && curr->size >= size) { // 尋找符合條件且最小的區塊(Best Fit),減少外部碎片 if (best_block == NULL || curr->size < best_block->size) { best_block = curr; } } // 精確前進當前區塊的實際大小,不論其內部被切得多碎,都能地毯式掃描 curr = buddy_block_next(curr); } if (best_block != NULL) { return buddy_block_split(best_block, size); } return NULL; } C_STATIC_FORCE_INLINE int buddy_block_size_required(c_Buddy_t *b, int size) { int actual_size = b->alignment; const int total_needed = size + b->alignment; // 預留足夠空間確保 padding 後依然夠用 while (actual_size < total_needed) { actual_size <<= 1; } return actual_size; } static void buddy_block_coalescence(c_BuddyBlock_t *head, c_BuddyBlock_t *tail) { for (;;) { c_BuddyBlock_t *curr = head; c_bool_t consolidated_any = C_FALSE; while (curr < tail) { c_BuddyBlock_t *next = buddy_block_next(curr); // 檢查安全邊界 if (next >= tail) { break; } // 凝聚條件:兩相鄰區塊皆空閒,且大小相等 // 注意:在夥伴系統中,左夥伴的偏移量必須是其兩倍大小的整數倍(對齊檢查) if (curr->is_free && next->is_free && curr->size == next->size) { const c_uintptr_t offset = (c_uintptr_t)curr - (c_uintptr_t)head; if ((offset % (curr->size << 1)) == 0) { curr->size <<= 1; // 融合!容量翻倍 consolidated_any = C_TRUE; // 融合後,下一次推進會自動從融合後的大區塊末端繼續,不用前進 next continue; } } // 若無法融合,正常步進到下一個區塊 curr = next; } // 如果整輪掃描下來沒有任何區塊可以再融合,代表凝聚完成,退出循環 if (!consolidated_any) { break; } } } /* ------------------------------------------------------------------------------------------------------------------ */ /* */ void c_Buddy_Init(c_Buddy_t *b, void *data, int size, int alignment) { assert(b != NULL); assert(data != NULL); assert(is_power_of_two(size) && "size is not a power-of-two"); assert(is_power_of_two(alignment) && "alignment is not a power-of-two"); // 確保對齊基準至少能放下一個標頭結構體 if (alignment < (int)sizeof(c_BuddyBlock_t)) { alignment = C_ALIGN_UPB(sizeof(c_BuddyBlock_t), 2); // 向上取 2 的冪次 while (!is_power_of_two(alignment)) { alignment++; // 穩健保險 } } assert((c_uintptr_t)data % alignment == 0 && "data is not aligned to minimum alignment"); b->alignment = alignment; b->head = (c_BuddyBlock_t *)data; b->head->size = size; b->head->is_free = C_TRUE; // 哨兵結尾 b->tail = buddy_block_next(b->head); } void *c_Buddy_Alloc(c_Buddy_t *b, int size) { if (!b || size <= 0) return NULL; int actual_size = buddy_block_size_required(b, size); // 第一階段:尋找現有最合適的空閒塊 c_BuddyBlock_t *found = buddy_block_find_best(b->head, b->tail, actual_size); if (found == NULL) { // 第二階段:若找不到,強制進行全面碎片凝聚(Coalesce),再搜尋一次 buddy_block_coalescence(b->head, b->tail); found = buddy_block_find_best(b->head, b->tail, actual_size); } if (found != NULL) { found->is_free = C_FALSE; return (void *)((uint8_t *)found + b->alignment); } return NULL; // OOM } void c_Buddy_Free(c_Buddy_t *b, void *data) { if (data != NULL) { assert((c_uintptr_t)b->head <= (c_uintptr_t)data); assert((c_uintptr_t)data < (c_uintptr_t)b->tail); c_BuddyBlock_t *block = (c_BuddyBlock_t *) ((uint8_t *) data - b->alignment); block->is_free = C_TRUE; // NOTE: Coalescence could be done now but it is optional // buddy_block_coalescence(b->head, b->tail); } }