頁表的建立
linux在啟動過程中,要首先進行記憶體的初始化,那麼就一定要首先建立頁表。我們知道每個程序都擁有各自的程序空間,而每個程序空間又分為核心空間和使用者空間。
以arm32為例,每個程序有4g的虛擬空間,其中0-3g屬於使用者位址空間,3g-4g屬於核心位址空間,核心位址空間是所有程序共享的,因此核心位址空間的頁表也是所有程序共享的。
linux核心中使用者程序記憶體頁表的管理是通過乙個結構體mm_struct來描述的:
struct mm_struct ;
這個結構體中的pgd成員就是代表著pgd頁表的存放位置,通過前面文章的介紹,我們知道pgd頁表項中存放的是下一級頁表的基位址,這樣通過它我們就可以進一步找到pud/pmd/pte後面的頁表了。
使用者程序頁表
程序頁表是存放在各自程序的task_struct中的,我們先來看下task_struct:
include/linux/sched.h:
struct task_struct ;
這個mm成員變數中就是存放的該程序對應的mm_struct結構體資料,通過它我們就可以知道對應程序的頁表了。
mm active_mm
使用者程序位址空間 活躍的使用者程序位址空間
active_mm成員是專門為核心程序引入的,核心程序是不需要訪問使用者位址空間的,也就是說mm成員是被設定為null的,那麼為了讓核心程序與普通使用者程序具有統一的上下文切換方式,當核心程序進行上下文切換時,讓核心程序的active_mm指向剛被排程出去的程序的active_mm,之所以引入這個機制,是為了節省context switch帶來的系統開銷,當我們發現要程序切換的是乙個核心程序(執行緒)時,由於我們不需要訪問使用者位址,那麼只需要借用上乙個程序的active mm配置即可,這樣一來,排程器就可以節省switch_mm的開銷了,由此可以很大提高系統效能。
static __always_inline struct rq *
context_switch(struct rq *rq, struct task_struct *prev,
struct task_struct *next, struct pin_cookie cookie)
else
switch_mm_irqs_off(oldmm, mm, next);
通過上面的函式可見,對於mm為空的情況,直接把active_mm 設定為prev->active_mm,這就是設定的核心執行緒的位址空間。而對於使用者程序,active_mm就被設定為等於mm,這一步是在fork的時候做的:
static int copy_mm(unsigned long clone_flags, struct task_struct *tsk)
retval = -enomem;
mm = dup_mm(tsk);
if (!mm)
goto fail_nomem;
good_mm:
tsk->mm = mm;
tsk->active_mm = mm;
return 0;
fail_nomem:
return retval;
}
fork執行的時候是會呼叫copy_mm函式的,此函式通過oldmm來判斷當前執行fork的是核心程序還是使用者程序,如果是oldmm為空,代表著要建立的是乙個核心程序,此時我們直接返回,如果是乙個使用者程序,那麼最後會設定 tsk->mm = mm; 並且 tsk->active_mm = mm; 。task_struct中的mm成員主要是記錄使用者位址空間,其中記錄的pgd是會最終配置到mmu中的ttbr0暫存器中的。
核心頁表
struct mm_struct init_mm = ;
/* to find an entry in a page-table-directory */
#define pgd_index(addr) ((addr) >> pgdir_shift)
#define pgd_offset(mm, addr) ((mm)->pgd + pgd_index(addr))
/* to find an entry in a kernel page-table-directory */
#define pgd_offset_k(addr) pgd_offset(&init_mm, addr)
/*
* create the page directory entries and any necessary
* are able to cope here with varying sizes and address
* offsets, and we take full advantage of sections and
* supersections.
*/
if ((md->type == mt_device || md->type == mt_rom) &&
md->virtual >= page_offset && md->virtual < fixaddr_start &&
(md->virtual < vmalloc_start || md->virtual >= vmalloc_end))
}
#define init_task(tsk) \
, \
......
核心頁表是如何在不同程序中共享的?
核心位址空間使用的ttbr1作為頁表基位址,而使用者位址空間是ttbr0作為頁表基位址,這樣我們只需要配置核心頁表後設定到ttbr1暫存器,後面再各個程序切換時,不對ttbr1做切換,即可共享這段記憶體配置,而使用者空間位址,我們在程序切換是需要進行切換,這個切換是通過task_struct中的mm_struct成員來做的。
深入淺出記憶體管理 記憶體節點 Node
本文以linux核心4.9來做介紹。typedef struct pglist data pg data t enum 如上所示支援的分配方式有兩種,zonelist fallback和zonelist nofallback,那麼根據不同的分配方式,對於zone的優先順序可能是不同的,這個陣列可以記...
深入淺出TFS 建立WorkItem
使用場景 在專案交付流程當中,我們在準備部署專案的時候,比如需要依次部署到dev qa和prod共3個不同的環境。我們需要由專門負責部署的部門integration team的人員來操作。這個時候我們需要通過在tfs中建立work item來記錄這件事情。操作步驟 主要有兩種方式,新建和拷貝已有的。...
Nginx 的深入淺出
1.什麼是nginx nginx是一款高效能的http 伺服器 反向 伺服器及電子郵件 imap pop3 伺服器。由俄羅斯的程式設計師igor sysoev所開發,官方測試nginx能夠支支撐5萬併發鏈結,並且cpu 記憶體等資源消耗卻非常低,執行非常穩定。2.nginx的應用場景 3.nginx...