提出問題:若驅動程序無法立即滿足請求,該如何響應? 比如:當數據不可用時調用read,或是在緩衝區已滿時,調用write
解決問題:驅動程序應該(默認)該阻塞進程,將其置入休眠狀態直到請求可繼續。
休眠:
當一個進程被置入休眠時,它會被標記爲一種特殊狀態並從調度器運行隊列中移走,直到某些情況下修改了這個狀態,才能運行該進程。
安全進入休眠兩原則:
1.永遠不要在原子上下文中進入休眠。(原子上下文:在執行多個步驟時,不能有任何的併發訪問。這意味着,驅動程序不能再擁有自旋鎖,seqlock,或是RCU鎖時,休眠)
2.對喚醒之後的狀態不能做任何假定,因此必須檢查以確保我們等待的條件真正爲真
臨界區 vs 原子上下文
原子上下本:一般說來,具體指在中斷,軟中斷,或是擁有自旋鎖的時候。
臨界區:每次只允許一個進程進入臨界區,進入後不允許其它進程訪問。
other question:
要休眠進程,必須有一個前提:有人能喚醒進程,而起這個人必須知道在哪兒能喚醒進程,這裏,就引入了“等待隊列”這個概念。
等待隊列:就是一個進程鏈表(我的理解:是一個休眠進程鏈表),其中包含了等待某個特定事件的所有進程。
等待隊列頭:wait_queue_head_t,定義在<linux/wait.h>
定義方法:靜態 DECLARE_QUEUE_HEAD(name)
動態 wait_queue_head_t my_queue;
init_waitqueue_head(&my_queue);
struct __wait_queue_head {
spinlock_t lock;
struct list_head task_list;
};
typedef struct __wait_queue_head wait_queue_head_t;
簡單休眠
linux最簡單的休眠方式是wait_event(queue,condition)及其變種,在實現休眠的同時,它也檢查進程等待的條件。四種wait_event形式如下:
wait_event(queue,condition);/*不可中斷休眠,不推薦*/
wait_event_interruptible(queue,condition);/*推薦,返回非零值意味着休眠被中斷,且驅動應返回-ERESTARTSYS*/
wait_event_timeout(queue,condition,timeout);
wait_event_interruptible_timeout(queue,conditon,timeout);/*有限的時間的休眠,若超時,則不管條件爲何值返回0*/
喚醒休眠進程的函數:wake_up
void wake_up(wait_queue_head_t *queue);
void wake_up_interruptible(wait_queue_head *queue);
慣例:用wake_up喚醒wait_event,用wake_up_interruptible喚醒wait_event_interruptible |
休眠與喚醒 實例分析:
本例實現效果爲:任何從該設備上讀取的進程均被置於休眠。只要某個進程向給設備寫入,所有休眠的進程就會被喚醒。
static DECLARE_WAIT_QUEUE_HEAD(wq); static int flag =0; ssize_t sleepy_read(struct file *filp,char __user *buf,size_t count,loff_t *pos) {
}
ssize_t sleepy_write(struct file *filp,const char __user *buf,size_t count,loff_t *pos) {
} |