? ? ? ? 正在執行的用戶態X切換用戶態進程Y的過程為系統中常用的情況,但并非不能完全準確地反應系統的全部執行場景,還有一些場景比較特殊,主要包括以下5種情況
? ? ? ? 一.內核線程之間通過中斷處理過程中的調度時機發生進程切換,與一般的情況非常類似,只是內核線程在運行過程中發生中斷,沒有進程用戶態和內核態的切換
? ? ? ? 二.用戶進程向內核線程的切換。比一般的情況更簡單,內核線程不需要從內核態返回用戶態,如果該內核是直接調用schedule函數主動讓出cpu的,那么它被重新調度執行時就沒有中斷上下文恢復現場的問題
? ? ? ? 三.內核線程向用戶線程的切換。如果內核線程主動調用schedule函數,只用進程上下文的切換,沒有發生中斷上下文切換,它比一般的情況也更簡單,但用戶進程從內核態返回用戶態依然需要中斷上下文恢復現場返回用戶態
? ? ? ? 四.創建的子進程第一次執行時的執行起點較為特殊,需要人為地創建一個進程上下文環境作為起始點。比如fork一個進程時,子進程不是從schedule函數中完成進程cpu關鍵上下文切換之后開始執行的,而是從ret_from_fork開始執行的:
????????1. ?子進程執行的上下文構造
- ?內核棧初始化?:
fork
創建子進程時,通過copy_thread
函數復制父進程的內核棧,并?手動設置子進程的指令指針(eip/rip)為ret_from_fork
?,而非父進程被中斷時的地址。
- ?寄存器狀態偽造?:子進程的寄存器上下文(如
eax
)被設置為0(表示子進程的fork返回值),其他寄存器從父進程復制,形成“偽中斷返回”環境。
????????2. ?ret_from_fork
的作用?
?中斷模擬入口?:該標簽是內核中斷返回的通用路徑,子進程通過此處?模擬從中斷返回用戶態?的過程,完成以下操作:
- 恢復用戶態寄存器(通過
restore_all
) - 執行開中斷操作(因進程切換時中斷默認關閉)
- 跳轉到用戶態指定地址(通常為
fork
后的下一條指令)。
與schedule
的差異?:schedule
負責進程切換時的資源調度,而ret_from_fork
是子進程?首次獲得CPU時的執行起點?,無需經歷完整的調度器上下文切換 ?
? ? ? ? 五、加載一個新的可執行程序execve系統調用返回用戶態的情況也較為特殊,需要人為地創建一個中斷上下文的現場。比如execvex系統調用加載新的可執行程序,在execve系統調用處理過程修改了觸發該系統調用保存的中斷上下文現場,使得返回用戶態的位置修改為新程序的elf_entry或者ld動態鏈接器的起點地址
?1. 用戶態程序主動調用?
-
?Shell執行命令?
當用戶在終端輸入命令(如ls
或./a.out
)時,Shell(如bash
)會通過fork()
創建子進程,并在子進程中調用execve
加載目標程序。
Shell → fork() → 子進程 → execve("/bin/ls", ...) → 替換為ls進程
? ? ? ? 通過分析總結,大致可以想象出Linux操作系統的一般執行過程過程,其中的關鍵點如下:
? ? ? ? 1.?中斷和中斷返回有中斷上下文的切換,也就是保存現場和恢復現場,cpu和內核代碼中斷處理程序入口的匯編語言代碼結合起來完成中斷上下文的切換
? ? ? ? 2.進程調度過程中有進程上下文的切換,而此切換完全由內核完成,具體包括:從一個進程的地址空間切換到另一個進程的地址空間;從一個進程的內核堆棧切換到另一個進程的內核堆棧;還有進程的cpu上下文關鍵上下文切換
????????linux內核通過中斷上下文切換和進程上下文這兩種基本的運行機制來保障為用戶提供最基本和最重要的服務,這些服務如下:
? ? ? ? 1、通過系統調用的形式為進程提供各種服務
? ? ? ? 2、通過中斷服務程序為I/O、內存管理等硬件的正常工作提供各種服務
? ? ? ? 3、通過內核線程為系統提供動態的維護服務,以及完成中斷服務中可延時處理的任務
????????