本週要繼續進行 Linux Device Driver 的教育訓練,正好上週有同學問到「process 狀態」的問題,原因是我們在講解範例時,提到 O'Reilly 的 Linux Device Driver 書上以「half sleep」來說明「手動變更 current 狀態」的做法,以及為何不直接呼叫 sleep_on() API 的原因。
當時只做了相當簡要的回答,同學也對 OS 書上講到的 process state 有些不了解。本週打算做比較深入的討論,結果發現我的 Linux Kernel 專欄休眠許久,「Process State」這個章節居然還沒有整理上來,因此在這裡補上這個部份,以免上課要講解時無料可用。
Process 的狀態(state)紀錄在 process descriptor 的 state 欄位。如果您對 process、fork(process creation)以及 preemptive 不熟悉的話,建議您先從頭依序閱讀「Linux Kernel 專欄」裡的文章,才能對以下的 process state 轉換圖產生一點感覺。
Linux 系統透過 fork system call 建立新的 process,當 process 被生出來後,他的狀態就是「執行中狀態」,也就是 TASK_RUNNING。不過 process 產生後,並不是馬上就能執行,必須被排程器挑選後做 context switch 才是「正在執行中」的 process。我們以 current 代表「正在執行中」的那一個 process,前面所謂的執行中狀態指的是被放在 task queue / run queue(OS 叫 ready queue)中的 process。當 current 正在執行時,很可能被其他 priority 更高的 process 搶奪執行權,這時 current 就會被放回 ready queue 裡,這是因為 Linux 是一個可搶先(preemptive)排程的作業系統。
好了,今天 current 要存取硬體,這時如果硬體裝置出現問題,無法讀寫資料,此時「Linux 驅動程式必須把 current 放到 wait queue 裡睡覺(等待)」。
Wait queue 就是用來讓 current 睡覺的 kernel API。
Process 被放到 wait queue 時的狀態為 TASK_INTERRUPTIBLE 或是 TASK_UNINTERRUPTIBLE。這個時候因為我們的 process 在睡覺了(被放到 wait queue),所以 scheduler 就會再由 ready queue 裡挑一個 process 來執行。
Wait queue 裡的 process 怎麼辦?
睡著的 process 必須被叫醒(wake up),這個動作一般是在 interrupt handler 裡做的。當 process 被叫起來後,狀態再度切換成 TASK_RUNNING 了,於是,又得到被 scheduler 挑選執行的權力了。
Process state 的定義可以在 include/linux/sched.h 裡找到(以下適用 2.6.24 版本以前):
#define TASK_RUNNING 0
#define TASK_INTERRUPTIBLE 1
#define TASK_UNINTERRUPTIBLE 2
Kernel 也提供了一個 API 可用來設定 current 的狀態:
set_current_state(state_value)
在驅動程式裡手動變更 process state 的目的是為了將 process 放到 wait queue 並達到 critical section 的效果。
Jollen's Blog 使用 Github issues 與讀者交流討論。請點擊上方的文章專屬 issue,或 open a new issue
您可透過電子郵件 jollen@jollen.org,或是 Linkedin 與我連絡。更歡迎使用微信,請搜尋 WeChat ID:jollentw