這個源檔案主要講的是頁分配的過程。
enum palloc_flags
{
PAL_ASSERT = 001, /* Panic on failure. */
PAL_ZERO = 002, /* Zero page contents. */
PAL_USER = 004 /* User page. */
};
頁分配時可以有三種狀態,
PAL_ASSERT:如果頁不能被分配,則kernel panics
PAL_ZERO:分配頁時清零。
PAL_USER:從user pool中分配頁。
前面兩種是從kernel pool中分配頁。
我們把記憶體分成兩種類型。一種是user pool,一種是kernel pool。
struct pool
{
struct lock lock; /* Mutual exclusion. */
struct bitmap *used_map; /* Bitmap of free pages. */
uint8_t *base; /* Base of pool. */
};
這裡我們用bitmap來表明閒置頁。這個和資料庫的位元影像索引等都是差不多的。
lock是為了在尋找bitmap的時候只能是原子的。
void
palloc_init (size_t user_page_limit)
{
/* Free memory starts at 1 MB and runs to the end of RAM. */
uint8_t *free_start = ptov (1024 * 1024); //起始從1MB開始
uint8_t *free_end = ptov (init_ram_pages * PGSIZE); //結束是ram的頁數*4KB
size_t free_pages = (free_end - free_start) / PGSIZE; //一共有幾頁空的
size_t user_pages = free_pages / 2; //如果一半空間不到user_page_limit,則不變,如果大於user_page_limit,則縮小為這個值。
size_t kernel_pages; //
if (user_pages > user_page_limit)
user_pages = user_page_limit;
kernel_pages = free_pages - user_pages; //其餘的閒置頁賦給核心。
/* Give half of memory to kernel, half to user. */
init_pool (&kernel_pool, free_start, kernel_pages, "kernel pool");
init_pool (&user_pool, free_start + kernel_pages * PGSIZE,
user_pages, "user pool");
}
這個是記憶體的分池,user_page_limit參數是為了限制使用者池的大小一定要在這個大小以內。
void *
palloc_get_multiple (enum palloc_flags flags, size_t page_cnt)
{
struct pool *pool = flags & PAL_USER ? &user_pool : &kernel_pool; //選擇pool的類型。
void *pages;
size_t page_idx;
if (page_cnt == 0) //需求的頁數量為0
return NULL;
lock_acquire (&pool->lock);
page_idx = bitmap_scan_and_flip (pool->used_map, 0, page_cnt, false); //尋找第一個連續page_cnt的空頁的頁位置,即是第幾個頁。
lock_release (&pool->lock);
if (page_idx != BITMAP_ERROR)
pages = pool->base + PGSIZE * page_idx; //找到頁具體位置
else
pages = NULL;
if (pages != NULL)
{
if (flags & PAL_ZERO)
memset (pages, 0, PGSIZE * page_cnt); //如果PAL_ZERO,則分配是還要清零。
}
else
{
if (flags & PAL_ASSERT)
PANIC ("palloc_get: out of pages");
}
return pages;
}
//-----------------------------------------------------------------------------------------------------
static bool
page_from_pool (const struct pool *pool, void *page)
{
size_t page_no = pg_no (page);
size_t start_page = pg_no (pool->base);
size_t end_page = start_page + bitmap_size (pool->used_map);
return page_no >= start_page && page_no < end_page;
}
pg_no是把虛擬位址轉為他所在的頁號,因此如果page_no在start_page和end_page之間,則說明這個頁已經分配了。
當free-page時要把這些頁設為0xcc。
//-------------------------------------------------------------------------------------------------------
static void
init_pool (struct pool *p, void *base, size_t page_cnt, const char *name)
//池中除了要放空閑頁,還要放bitmap,這個是用來記錄的。因此bm_pages就是bitmap所佔的頁數。
p池為從base開始page_cnt頁數的一個池,。
{
size_t bm_pages = DIV_ROUND_UP (bitmap_buf_size (page_cnt), PGSIZE);
if (bm_pages > page_cnt) //如果分配給池的大小還不能裝的下bitmap。則不夠。
PANIC ("Not enough memory in %s for bitmap.", name);
page_cnt -= bm_pages; //page_cnt-bm_pages為真正閒置頁數。
printf ("%zu pages available in %s./n", page_cnt, name);
/* Initialize the pool. */
lock_init (&p->lock);
p->used_map = bitmap_create_in_buf (page_cnt, base, bm_pages * PGSIZE);
p->base = base + bm_pages * PGSIZE; //池的基地址是原來的base+bitmap_page*PGSIZE;這才是真正的基地址。池的base是指除了bitmap空間的基地址。
}
高
| || <-----整體是一個pool
|--------------------------------------------------------------------- || <-----page_get_multiple()後返回的指標
| 分配的空間 || 地址
| ||
|----------------------------------------------------------------------|| <-----base (一直不會變)
|DIV_ROUND_UP (bitmap_buf_size (page_cnt), PGSIZE);|| <-----page_cnt要用的空間
|----------------------------------------------------------------------|| |低