为了实现First-Fit算法,应该用一些列表来管理空闲的内存块;
free_area_t 这个结构是用来管理空闲内存块的,列表结构都定义在了 lib/list.h 文件中;
list.h
struct list_entry {
struct list_entry *prev, *next; //这是一个双链表结构
};
memlayout.h
typedef struct {
list_entry_t free_list; // the list header
unsigned int nr_free; // # 空闲列里的空闲页
} free_area_t;
- 所以default_init()应该写成:
free_area_t free_area;
#define free_list (free_area.free_list)
#define nr_free (free_area.nr_free)
static void
default_init(void) {
list_init(&free_list);
nr_free = 0; //初始化时空闲页为0
}
其中list_init()函数长这个样子:
static inline void
list_init(list_entry_t *elm) {
elm->prev = elm->next = elm; //双向链表初始化,头尾都指向头节点
}
- default_init_memmap()
首先Page的结构体:
struct Page {
int ref; // page frame's reference counter
uint32_t flags; // array of flags that describe the status of the page frame
unsigned int property; //空闲块的数量
list_entry_t page_link; // 空闲页链接
};
default_init_memmap() 函数:
static void default_init_memmap(struct Page *base, size_t n) { //该函数用来初始化一个空闲块
assert(n > 0);
struct Page *p = base; //首先将基址base赋给p
for (; p != base + n; p ++) { //n为页数,遍历n页直到结束
assert(PageReserved(p));
p->flags = p->property = 0; //如果该页空闲且不是空闲块的第一页,则 p->property = 0;
set_page_ref(p, 0); //因为p空闲且没有被引用
}
base->property = n; //如果该页空闲且是空闲块的第一页,则 p->property 等于所有块的数量;
SetPageProperty(base);
nr_free += n; //最后加上空闲块的数量
list_add(&free_list, &(base->page_link)); //起始页加入空闲页链表
}
- default_alloc_pages() 函数:
static struct Page *
default_alloc_pages(size_t n) { //寻找第一个空闲的页
assert(n > 0);
if (n > nr_free) { //若n大于连续空闲页数量,则退出
return NULL;
}
struct Page *page = NULL;
list_entry_t *le = &free_list;
while ((le = list_next(le)) != &free_list) { //遍历空闲链表,在空闲链表free_list中查找第一个符合条件的空闲页
struct Page *p = le2page(le, page_link);
if (p->property >= n) { //若当前页的连续空闲页数量大于等于n,则可以分配
page = p;
break;
}
}
if (page != NULL) {
list_del(&(page->page_link)); //从空闲页中删除该页,表明该页已被使用
if (page->property > n) { //如果该页的空闲大小比n大,则只分配n个空间
struct Page *p = page + n; //分配了n个空间,将偏移指针移到第n个的后一位
p->property = page->property - n; //p的容量减小n,表明p被占用了n个空间
list_add(&free_list, &(p->page_link)); // 将p剩下的空间加入空闲列表
}
nr_free -= n; //空闲链表总容量减小n
ClearPageProperty(page);
}
return page;
}
list_next函数:
list_next(list_entry_t *listelm) {
return listelm->next;
}
- default_free_pages 函数
static void default_free_pages(struct Page *base, size_t n) {
assert(n > 0);
struct Page *p = base;
for (; p != base + n; p ++) {
assert(!PageReserved(p) && !PageProperty(p));
p->flags = 0;
set_page_ref(p, 0);
}
base->property = n;
SetPageProperty(base);
list_entry_t *le = list_next(&free_list);
while (le != &free_list) {
p = le2page(le, page_link);
le = list_next(le);
if (base + base->property == p) { //如果空闲页起始页在 当前页的前面,进行合并
base->property += p->property; //起始页的总空闲页数量加上当前页的数量
ClearPageProperty(p);
list_del(&(p->page_link)); //将当前页删除
}
else if (p + p->property == base) { //如果空闲页起始页在 当前页的后面,进行合并
p->property += base->property; //同前
ClearPageProperty(base);
base = p; //起始页变成当前页
list_del(&(p->page_link)); //同前
}
}
nr_free += n; //空闲页总数量加上n
list_add(&free_list, &(base->page_link)); //加上当前页
}