每個CPU有固定的TSS(任務狀態(tài)段),TSS保存有當前任務的系統(tǒng)堆棧指針SS0和ESP0,切換任務時只是改變SS0和ESP0的值。
進程和線程都有自己獨立的系統(tǒng)堆棧和task_struct,如果沒有用戶空間的線程,為內(nèi)核線程。線程共享用戶空間,進程之間用戶空間獨立。每個線程的task_struct和系統(tǒng)空間堆棧結(jié)構(gòu)(7KB):

進程fork時,用戶空間的拷貝是通過復制頁面表暫時共享這個頁面,在子進程(或父進程)真的要寫這個頁面時再來分配頁面。(copy on write)
進程退出時,會釋放task_struct中的各種資源,但是task_struct和系統(tǒng)空間堆棧所在的兩個頁面并不會釋放。同時進程狀態(tài)變?yōu)門ASK_ZOMBIE。之后通過調(diào)用exit_notify通知父進程料理后事。
如果父進程先于子進程去世,則會將子進程托付給init進程。
進程的狀態(tài):
- TASK_RUNNING: 可以被執(zhí)行,被放入調(diào)度隊列
- TASK_INTERRUPTIBLE:睡眠狀態(tài),可被中斷,一般睡眠是這種
- TASK_UNINTERRUPTIBLE:睡眠裝態(tài)不可被中斷
- TASK_ZOMBIE:進程已去世,但還未被注銷
- TASK_STOPPED:調(diào)試掛起狀態(tài)
進程狀態(tài)轉(zhuǎn)換

task_struct鏈接入3個隊列
-
通過父兄指針
Paste_Image.png pidhash hash表,每個pid生成一個hash,同一hash的task_struct通過pidhash_next 和pidhash_pprev放入同一個隊列
通過next_task 和 prev_task 放入一個系統(tǒng)全局隊列
調(diào)度
內(nèi)核態(tài)通過schedule(), 用戶態(tài)通過pause(),引發(fā)一次調(diào)度(自愿)
linux的調(diào)度方式是有條件的可剝奪。當進程在用戶空間運行時,一旦有必要(比如運行了足夠長的時間),內(nèi)核可以剝奪其運行而調(diào)度其他進程,而當進程進入內(nèi)核態(tài)時就不能進行剝奪了,因為調(diào)度都是發(fā)生在從用戶態(tài)進入中斷或者異常處理,返回用戶態(tài)時進行調(diào)度(task_struct的need_resched需要設置為true:自愿讓出運行,系統(tǒng)調(diào)用受阻,時鐘中斷服務程序發(fā)現(xiàn)當前進程運行太久)。
調(diào)度政策根據(jù)進程的優(yōu)先級進行調(diào)度,運行時間越長優(yōu)先級越低,當所有進程優(yōu)先級為0時,重新計算優(yōu)先級。
被動調(diào)度:need_resched被置為1,從內(nèi)核空間進入用戶空間時,會進行調(diào)度,這時task狀態(tài)還為TASK_RUNNING,有可能還會被調(diào)度上
- 當前進程的counter減為0時,每次時鐘中斷會將counter減1
- 喚醒另一個進程,被喚醒進程的優(yōu)先級更高
- 一個進程通過yield系統(tǒng)調(diào)用讓路
主動調(diào)度:task狀態(tài)變?yōu)門ASK_INTERRUPTIBLE或者TASK_UNINTERRUPTIBLE
- read(), write(), open() 這種系統(tǒng)調(diào)用受阻而進入睡眠
- nanosleep(),pause() 系統(tǒng)調(diào)用
內(nèi)核中的互斥操作:
- semaphore 信號量(防止死鎖的方法:不要在一個臨界區(qū)進入另一個臨界區(qū);進入臨界區(qū)的順序一致)
- spin_lock:防止其他處理器中斷或進程的干擾,得不到鎖的處理器會一直空轉(zhuǎn)
