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)進程上下文切換。