對於一個進程"睡眠"意味着什么? 當一個進程被置為睡眠, 它被標識為處於一個特殊的狀 態並且從調度器的運行隊列中去除. 直到發生某些事情改變了那個狀態, 這個進程將不被 在任何 CPU 上調度, 並且, 因此, 將不會運行. 一個睡着的進程已被擱置到系統的一邊, 等待以后發生事件.
對於一個 Linux 驅動使一個進程睡眠是一個容易做的事情. 但是, 有幾個規則必須記住 以安全的方式編碼睡眠.
這些規則的第一個是: 當你運行在原子上下文時不能睡眠. 我們在第 5 章介紹過原子操 作; 一個原子上下文只是一個狀態, 這里多個步驟必須在沒有任何類型的並發存取的情況 下進行. 這意味着, 對於睡眠, 是你的驅動在持有一個自旋鎖, seqlock, 或者 RCU 鎖時 不能睡眠. 如果你已關閉中斷你也不能睡眠. 在持有一個旗標時睡眠是合法的, 但是你應 當仔細查看這樣做的任何代碼. 如果代碼在持有一個旗標時睡眠, 任何其他的等待這個旗 標的線程也睡眠. 因此發生在持有旗標時的任何睡眠應當短暫, 並且你應當說服自己, 由 於持有這個旗標, 你不能阻塞這個將最終喚醒你的進程.
另一件要記住的事情是, 當你醒來, 你從不知道你的進程離開 CPU 多長時間或者同時已 經發生了什么改變. 你也常常不知道是否另一個進程已經睡眠等待同一個事件; 那個進程 可能在你之前醒來並且獲取了你在等待的資源. 結果是你不能關於你醒后的系統狀態做任 何的假設, 並且你必須檢查來確保你在等待的條件是, 確實, 真的.
一個另外的相關的點, 當然, 是你的進程不能睡眠除非確信其他人, 在某處的, 將喚醒它. 做喚醒工作的代碼必須也能夠找到你的進程來做它的工作. 確保一個喚醒發生, 是深入考 慮你的代碼和對於每次睡眠, 確切知道什么系列的事件將結束那次睡眠. 使你的進程可能 被找到, 真正地, 通過一個稱為等待隊列的數據結構實現的. 一個等待隊列就是它聽起來 的樣子:一個進程列表, 都等待一個特定的事件.
在 Linux 中, 一個等待隊列由一個"等待隊列頭"來管理, 一個 wait_queue_head_t 類型 的結構, 定義在<linux/wait.h>中. 一個等待隊列頭可被定義和初始化, 使用:
DECLARE_WAIT_QUEUE_HEAD(name);
或者動態地, 如下:
wait_queue_head_t my_queue; init_waitqueue_head(&my_queue);
我們將很快返回到等待隊列結構, 但是我們知道了足夠多的來首先看看睡眠和喚醒.