Linux 進程切換 0.11與2.4的比較

0.11的進程模型與2.4不同。0.11中每個進程都有一個tss結構,用於保存/恢復進程切換時的現場(主要都是一些寄存器);而2.4中每個cpu使用一個tss結構,多個進程將共用一個tss。因此,0.11的進程切換使用了CPU的硬件特性;而2.4的切換則是一種軟切換,從CPU的角度來看,實際上沒有進程切換,只不過是修改了若干寄存器而已。

看進程切換的代碼必須注意一點:內核空間和用戶空間。所有進程的內核空間是共享的,即內核空間線性地址及對應的物理地址是相同的;而用戶空間是各自獨立的。此外,各個進程的內核態堆棧是各自獨立的。

進程切換必須得從中斷說起。進程創建涉及系統調用,系統調用實際也是一種中斷。進程切換涉及時鐘中斷。一般來說,進入中斷程序(不論哪種中斷)後首先需要保存一些寄存器(即現場保護),在退出中斷程序之前需要恢復一些寄存器(即現場恢復),這兩個過程在0.11和2.4內核中都是一樣的。

0.11內核和2.4內核代碼裏均有一個方法——switch_to,此方法負責進程切換。0.11內核的代碼相對簡單,因爲她使用了CPU的硬件特性,因此只需通過一個長跳轉指令,跳轉的新進程的tss即可。剩下的工作就交給CPU了,CPU首先需要將執行跳轉指令時的寄存器數據保存到原進程的tss中,然後將用新進程的tss恢復寄存器數據,之後就接着執行eip所指向的下一條指令即可。

2.4內核的切換過程稍微複雜一些,實際上只是看上去代碼量多些,但之際執行效率可能會更好。假設系統只有一個CPU,則2.4內核所有進程就共用一個tss。因此在切換時需要先保存原進程的幾個寄存器值。從代碼來看,也就保存了eip、esp,這兩個寄存器太重要了。其中eip值存儲的是原進程下次被切換執行時的下一條指令地址。之後,就是用新進程任務數據結構中的的esp值來恢復esp寄存器。到此基本就完成切換了。看起來代碼很多,但實際涉及的數據保存恢復很少,原因就在於每個進程在被中斷時已經保存了現場,而中斷返回又恢復了現場。所以進程的切換重點就是對eip和esp等關鍵寄存器的操作。

0.11內核看似代碼簡單,但由於它也涉及中斷現場保存和回覆,此外還要進行tss的保存和恢復,因此實際性能反而不如2.4的軟切換方式。由此可見,tss中的那一堆寄存器存儲恢復操作顯得很多餘,實際上比較有用的寄存器也就是esp、eip以及標誌寄存器等。2.4採用一個CPU一個tss的方式非常明智(tss是不能省略的,要不就不能進行用戶態和內核態的切換了)。

0.11與2.4的進程創建過程也不一樣。0.11在創建新進程時需要設置新進程任務數據結構中的tss。之後就完事了,新進程在新建之後其內核態堆棧是空的,當新進程第一次被切換執行時,實際上直接就切換到用戶態了,因爲tss裏存儲的是父進程執行fork時的現場狀態。
2.4內核就不太一樣了,因爲所有進程都共用一個tss,所以不可能把父進程的現場狀態存儲在tss中。2.4所採用的方法是將父進程執行fork時的現場狀態保存到新進程的內核態堆棧上(見arch/i386/kernel/process.c中的copy_thread方法。每個進程的內核態堆棧是獨立的)。當新進程第一次被切換執行時並不立即進入用戶態,而是跳轉到中斷返回的代碼,將內核態堆棧上的數據恢復到寄存器之後執行中斷返回。
發佈了99 篇原創文章 · 獲贊 69 · 訪問量 78萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章