Linux 核心子系統的組成
由以上7個子系統組成。
一、記憶體管理子系統
職能:
1、從虛擬位址到物理地址映射的管理。
2、實體記憶體分配的管理。
地址映射管理
2.1虛擬位址空間分布
在Linux中使用的是虛擬位址,但是在訪問硬體的時候使用的是物理地址。比如程式中用malloc函數分配的都是虛擬位址,但是硬體在使用時用的是物理地址,這其中就有一個轉化關係。
它所支援的虛擬位址空間是由硬體地址匯流排寬度決定的,比如32位地址匯流排支援4GB虛擬記憶體。
使用者空間(0-3G):使用者程式。
核心空間(3-4G):直接映射區3G-3G+896MB.
Vmalloc區,
永久核心映射,
固定映射的線性地址。
2.2虛擬位址轉化為物理地址
CR3存放了頁目錄的基地址。
高10位和CR3寄存器相加,就可以找到頁目錄裡的頁目錄項。
頁目錄項裡存放的是頁表的基地址。
頁表的基地址再加上中間10位的值就可以找到物理頁。
物理頁再加上最後12位的位移就可以找到物理頁(通常4k)的儲存單元了。
直接映射區裡:虛擬位址=3G+物理地址
Vmalloc區:可以映射到高端和低端記憶體
永久映射區:高端記憶體
固定映射的線性地址:固定訪問一些寄存器
實體記憶體的分配
程式通過malloc等函數先申請到虛擬位址,當需要用到物理地址時通過請頁異常獲得物理地址。通過Kmalloc得到的虛擬位址時,虛擬位址和物理地址已經綁定了。
二、進程管理子系統
程式:存放在磁碟上的一系列代碼和資料的可執行映像,是一個靜止的實體
進程:是一個執行中的程式,他是動態實體。
進程四要素
1.有一段程式供其執行。這段程式不一定是某個進程所專有,可以與其他進程共用。
2.有進程專用的核心空間堆棧。
3.在核心中有一個task_struct資料結構,即通常所說的“進程式控制制塊”。有了這個資料結構,進程才能成為核心調度的一個基本單位接受核心的調度。
4.有獨立的使用者空間
Linux進程狀態
1.TASK_RUNNING
進程正在被CPU執行,或者已經準備就緒,隨時可以執行。當一個進程剛被建立時,就處於TASK_RUNNING狀態。
2.TASK_INTERRUPTINLE
處於等待中的進程,等待條件為真時被喚醒,也可以被訊號或者中斷喚醒。
3.TASK_UNINTERRUPTINLE
處於等待中的進程,待資源有效時喚醒,但不可以由其它進程通過(signal)或中斷喚醒。
4.TASK_KILLABLE
Linux2.6.25新引入的進程睡眠狀態,原理類似於TASK_UNINTERRUPTIBLE,但是可以被致命訊號(SIGKILL)喚醒。
5.TASK_TRACED
正處於被調試狀態的進程
6.TASK_DEAD
進程退出時(調用do_exit),所處的狀態。
Linux進程的描述
在linux核心代碼中,線程、進程都使用結構task_struct(sched.h)來表示,它包含了大量描述進程/線程的資訊,其中比較重要的有:
Pid_t pid; //進程號
Long state;//進程狀態
Int prio;//進程優先順序
Linux進程調度
學習調度需要掌握哪些知識點
1、調度策略
即時進程的優先順序比普通進程高。
SCHED_NORMAL(SCHED_OTHER):普通的分時進程
SCHED_FIFO:先入先出的即時進程
SCHED_RR:時間輪轉的即時進程
SCHED_BATCH:批處理進程
SCHED_IDLE:只在系統空閑時才能被調度執行的進程
2、調度時機
即schedule()函數什麼時候被調用。
主動式:
在核心中直接調用schedule()。當進程需要等待資源等而暫時停止運行時,會把自己的狀態置於掛起(睡眠),並主動請求調度,讓出CPU。
範例:
1、current->state = TASK_INTERRUPTIBLE;
2、Schedule();
Current是一個指標,指向當前正在啟動並執行進程的task_struct。
被動式:搶佔式
分為:使用者態搶佔(linux2.4、linux2.6)和核心態搶佔(linux2.6)。
使用者搶佔發生在:
從系統調用返回使用者空間。
從中斷處理常式返回使用者空間。
核心即將返回使用者空間的時候,如果need_resched標誌被設定,會導致schedule()被調用,即發生使用者搶佔。
當某個進程耗盡他的時間片時,會設定need_resched標誌
當一個優先順序更高的進程進入可執行狀態的時候,也會設定need_resched標誌。
使用者態搶佔缺陷
進程/線程一旦運行到核心態,就可以一直執行,直到它主動放棄或時間片耗盡為止。這樣會導致一些非常緊急的進程或線程將長時間得不到運行,降低整個系統的即時性。
改進方式
允許系統在核心態也支援搶佔,更高優先順序的進程/線程可以搶佔正在核心態啟動並執行低優先順序進程/線程。
核心搶佔可能發生在:
中斷處理常式完成,返回核心空間之前。
當核心代碼再一次具有可搶佔性的時候,如解鎖及使能非強制中斷等。
在支援核心搶佔的系統中,某些特例下是不允許搶佔的;
1核心正在運行中斷處理。
2核心進行中中斷內容相關的Bottom Half (中斷的底半部)處理。
硬體中斷返回前會執行非強制中斷,此時仍然處於中斷上下文中。
3進程正持有spinlock自旋鎖、writelock/readlock讀寫鎖等,
當持有這些鎖時,不應該被搶佔,否則由於搶佔將可能導致其他進程長期得不到鎖,而讓系統處於死結狀態。
4核心正在執行發送器scheduler。搶佔的原因就是為了進行新的調度,沒有理由將發送器搶佔掉再運行發送器。
為保證linux核心在以上情況下不會被搶佔,搶佔式核心使用了一個變數preempt_count,稱為核心搶佔計數。這一變數被設定在進程的thread_info結構中。每當核心要進入以上幾種狀態時,變數preempt_count就加1,指示核心不允許搶佔。每當核心從以上幾種狀態退出時,變數preempt_count就減1,同時進行可搶佔的判斷與調度。
3、調度步驟
Schedule函數工作流程如下
1)清理當前運行中的進程;
2)選擇下一個要啟動並執行進程;
3)設定新進程的運行環境。
4)進程環境切換。