# BUAA_OS_lab2上机Extra解题记录

2022.4.14

## 2. 思路:

typedef LIST_ENTRY(Buddy) Buddy_list_entry;

struct Buddy {
u_long i; // 量度所管理Buddy内存空间的大小
u_long alloc_size; // 主要用于区分内存块是否被分配出去
};

struct Buddy *buddys;

struct Buddy_list buddy_free_list;

#define buddy_begin 0x02000000
#define buddy_end 0x04000000
#define buddy2pa(buddy) (u_long)( ((buddy)-buddys)*0x1000 + buddy_begin )
#define pa2buddy(pa) ( buddys + (( (pa) - buddy_begin  )>>12) )


### buddy_init函数

buddy_init用于初始化Buddy系统。此时，我们需要申请空间建立buddys数组（可以穿在buddy_free_list上的元素），并将初始的8块4MB空间放到空闲Buddy列表中。

void buddy_init(void) {
struct Buddy *buddy;
u_long MB4 = (1<<22);
u_long nbuddy = npage >> 1;
buddys = (struct Buddy *)alloc(sizeof(struct Buddy) * nbuddy, BY2PG, 1); // 申请空间
LIST_INIT(&buddy_free_list); // 初始化空闲链表
buddy->i = 10; buddy->alloc_size = 0;
}
}


### buddy_alloc

int buddy_alloc(u_int size, u_int *pa, u_char *pi) {
struct Buddy *buddy = 0; // 我们要分配的buddy空间
struct Buddy *temp; // 用于迭代
struct Buddy *splitBuddy;
LIST_FOREACH(temp, &buddy_free_list, link) { // 找到足够大、未分配的Buddy
if (temp->alloc_size == 0 && ( 1<<(temp->i + 12) ) >= size) {
buddy = temp;
break;
}
}
if (buddy == 0) return -1; // 未找到
else {
while ( (1<<(buddy->i + 11)) >= size && buddy->i != 0 ) { // 不满足结束条件，则将buddy迭代分割，直到满足结束条件
buddy->i = buddy->i - 1; // 拆分后大小缩小为一半
splitBuddy->i = buddy->i;
}
buddy->alloc_size = 1 << (buddy->i + 12);
*pa = buddy2pa(buddy);
*pi = buddy->i;
return 0;
}
}


buddy_alloc的时间复杂度为O(n).

## buddy_free

void buddy_free(u_int pa) {
struct Buddy *buddy = pa2buddy(pa);
struct Buddy *pair, *temp, *now;
buddy->alloc_size = 0;

else {
now = 0;
if (temp <= buddy) now = temp;
}
if (now != 0) LIST_INSERT_AFTER(now, buddy, link);
}
while(1) {
if(buddy->i == 10) return; // 4MB
pairAddr = buddy2pa(buddy) ^ ( 1 << (buddy->i + 12) ); // pair Buddy's addr
pair = pa2buddy(pairAddr); // pair Buddy's struct pointer
if (pair->alloc_size == 0 && pair->i == buddy->i) { // meet merge conditions: free; equal size.
mergedAddr = ( buddyAddr & ( ~( 1 << (buddy->i + 12) ) ) );

// 错误：没有意识到其中两项是相同的！只需要删除一项就行了。

buddy->alloc_size = 0;
}
else break;
}
}


1. 链表为空: 直接插入尾部即可