驅動開發之始,(四)阻塞型I O,程序休眠

2021-10-04 18:50:33 字數 2916 閱讀 8988

在前面的章節中,我們講述了read和write方法。當資料不可用時,使用者呼叫read,或者使用者使用寫入資料,但輸出緩衝區已滿,驅動程式該如何相應呢?在這種情況下,驅動程式應該(預設)阻塞該程序,將其置入休眠狀態直到請求可繼續。

1.休眠(sleep)

當乙個程序被置入休眠時,它會被標記為一種特殊狀態並從排程器的執行佇列中移走,休眠中的程序會被擱置在一邊,等待將來的某個事件發生,直到某些情況下修改了這個狀態,程序才會在任意cpu上被排程。

為將程序以安全的方式進入休眠,必須遵守兩條規則:

1.永遠不要在原子上下文(在執行多個步驟時,不能有任何的併發訪問)中進入休眠。

a.對休眠來說,驅動程式不能在擁有鎖是休眠。

b.禁止中斷時不能休眠。

c.擁有訊號量時可以休眠,但要保證休眠的**很短,並且還要確保擁有訊號量不會阻塞最終喚醒自己的那個程序。

2.必須檢查確保休眠等待的條件為真。

我們無法知道休眠期間發生了什麼事,無法知道是否還有其他程序在同一事件上休眠,這個程序可能在驅動被喚醒之前拿走該程序等待的資源。

關於休眠的另乙個問題,我們需要確定是否有其他程序會喚醒被休眠的程序,並且清楚地知道對每個休眠而言,哪些事件會結束休眠。能夠找到休眠的程序意味著,需要維護乙個稱為等待佇列的資料結構,等待佇列就是乙個程序鍊錶,其中包含了等待某個特定事件的所有程序。

在linux中,乙個等待佇列通過乙個「等待佇列頭」(wait queue head)來管理,等待佇列頭是乙個型別為wait_queue_head_t,在中可用過靜態定義並初始化乙個等待佇列頭:

declare_wait_queue_head(name);
使用動態方法:

wait_queue_head_t my_queue;

init_waitqueue_head(&my_queue)

2.簡單休眠

當乙個休眠程序被喚醒時,它必須再次檢查它所等待的條件的確為真,linux核心中最簡單的休眠方式是wait_event

#define wait_event(wq, condition) 					\

do while (0)

#define __wait_event(wq, condition) \

do \

finish_wait(&wq, &__wait); \

} while (0)

@wq是等待佇列頭,注意它是通過「值傳遞」

@condition是乙個c表示式,在事件為真之前,程序保持休眠

最好選擇wait_event_interruptible(),它可被訊號中斷

#define wait_event_interruptible(wq, condition)				\

()#define __wait_event_interruptible_timeout(wq, condition, ret) \

do \

ret = -erestartsys; \

break; \

} \

if (!ret && (condition)) \

ret = 1; \

finish_wait(&wq, &__wait); \

} while (0)

用來喚醒休眠程序的基本函式是wake_up

#define wake_up(x)			__wake_up(x, task_normal, 1, null)

void __wake_up(wait_queue_head_t *q, unsigned int mode,

int nr_exclusive, void *key)

@q是等待佇列

@mode 哪乙個執行緒

@多少個執行緒需要被喚醒

@key 可設定為null

wake_up_interruptible只會喚醒那些執行可中斷休眠的程序

#define wake_up_interruptible(x)	__wake_up(x, task_interruptible, 1, null)

void __wake_up(wait_queue_head_t *q, unsigned int mode,

int nr_exclusive, void *key)

在使用中,約定wait_event時使用wait_up,在使用wait_event_interruptible時使用wake_up_interruptible。

3.程序如何休眠

在檔案中,wait_queue_head_t型別的資料結構,它由乙個自旋鎖和乙個鍊錶組成。鍊錶中儲存的是乙個等待佇列入口,該入口宣告為wait_queue_t型別

struct __wait_queue_head ;

typedef struct __wait_queue_head wait_queue_head_t;

將程序置於休眠

step1:通常是分配並初始化乙個wait_queue_t結構,然後將其加入到對應的等待佇列。

step2:設定程序的狀態,將其標記為休眠,在中定義了多個任務狀態

#define task_running		0

#define task_interruptible 1

#define task_uninterruptible 2

task_running表示程序可執行。有兩個狀態表明程序處於休眠狀態:task_interruptible和task_uninterruptible。

核心驅動 阻塞型驅動

1 定義 等待佇列頭部 wait queue head t key q 2 初始化 等待佇列頭部 init waitqueue head key q 3 等待事件發生 wait event key q,key num 4 喚醒等待事件 wake up key q 查詢按鍵狀態 key.c inclu...

阻塞型驅動設計

阻塞型驅動設計 1.阻塞的必要性 當乙個裝置無法立刻滿足使用者的讀寫請 求時應當如何處理?例如 呼叫read 時,裝置沒有資料提供,但以後可能會 有 或者乙個程序試圖向裝置寫入資料,但是裝置暫時沒有準備好接收資料。當 上述情況發生的時候,驅動程式應當 預設地 阻塞程序,使它進入等待 睡 眠 狀態,直...

linux裝置驅動(8)阻塞型IO

當驅動程式無法立即滿足請求,該如何響應?如當我們想要寫入的時候,裝置對應的緩衝區已滿,或者是當我們想要讀的時候當前緩衝區是空的。為了提高cpu的效率,我們的驅動程式應該阻塞等待該程序,將其置於休眠狀態直到請求可繼續。休眠 sleep 對於程序來講意味著什麼?當乙個程序被置入休眠時,他會被標記為一種特...