原文**:等待佇列,poll_it利刃出鞘的部落格-csdn部落格
見《linux裝置驅動開發詳解》=> 8.1.1 等待佇列
poll_wait()退出迴圈的條件
(1)count非0,超時、有訊號等待處理
(2)發生錯誤
(3)我們的驅動程式裡註冊的poll函式返回值非0
wait_event_interruptible()
成功地喚醒乙個被wait_event_interruptible()的程序,需要滿足:
(1)condition為真的前提下 (2) 呼叫wake_up()。
condition一般宣告為static volatile int型別
wait_event_interruptible的返回值
根據 wait_event_interruptible 的巨集定義知:
1) 條件condition為真時呼叫這個函式將直接返回0,而當前程序不會
被 wait_event_interruptible和從runqueue佇列中刪除。
2) 如果要被wait_event_interruptible的當前程序有nonblocked pending
signals, 那麼會直接返回-erestartsys(i.e. -512),當前程序不會
被wait_event_interruptible 和從runqueue佇列中刪除。
3) 其他情況下,當前程序會被正常的wait_event_interruptible,並從
runqueue佇列中刪除,進入task_interruptible狀態退出執行排程,
直到再次被喚醒加入runqueue佇列中後而參與排程,將正常返回0。
wait_event_interruptible
#define wait_event_interruptible(wq, condition) \
() 注: c語言中的的值等於最後一項,即x,因此上述
巨集的值是 __ret。
#define __wait_event_interruptible(wq, condition, ret) \
do \
ret = -erestartsys; \
break; \
} \
finish_wait(&wq, &__wait); \
} while (0)
總結一下poll機制//驅動中定義
static declare_wait_queue_head(read_wq);
(fs/select.c)
syscall_define3(poll, struct pollfd __user *, ufds, unsigned int, nfds, int, timeout_msecs)
//設定超時時間
poll_select_set_timeout
do_sys_poll(ufds, nfds, to);
struct poll_wqueues table;
poll_initwait(&table);
init_poll_funcptr(&pwq->pt, __pollwait);
//此函式會在驅動中呼叫poll_wait時呼叫
pwq->p->_qproc = __pollwait;
do_poll(nfds, head, &table, end_time);
for(;;)
count++;
pt->_qproc = null;
}if (count || timed_out)
break;
if (!poll_schedule_timeout(wait, task_interruptible, to, slack))
timed_out = 1;
}wait_event_interruptible(read_queue_head, ev_write); //include/linux/wait.h
int __ret = 0;
if (!(ev_write))
__wait_event_interruptible(wq, condition, __ret); //include/linux/wait.h
define_wait(__wait); //include/linux/wait.h
define_wait_func(__wait, autoremove_wake_function)
//autoremove_wake_function:喚醒等待佇列wait中的thread,成功喚醒則清空等待佇列wait
wait_queue_t __wait =
for (;;)
ret = -erestartsys;
break;
}
finish_wait(&wq, &__wait);
原始碼分析:
wait_event_interruptible()分析:
讀一下wait_event_interruptible()的原始碼,不難發現這個函式先將 當前程序的狀態設定成task_interruptible,如果condition為假,呼叫schedule(), 而schedule()會將位於task_interruptible狀態的當前程序從runqueue 佇列中刪除。從runqueue佇列中刪除的結果是,當前這個程序將不再參 與排程,除非通過其他函式將這個程序重新放入這個runqueue佇列中, 這就是wake_up()的作用了。
由於這一段**位於乙個由condition控制的for(;;)迴圈中,所以當由 shedule()返回時(當然是被wake_up之後,通過其他程序的schedule()而再次排程本程序),如果條件condition不滿足,本程序將自動再次被設 置為task_interruptible狀態,接下來執行schedule()的結果是再次被 從runqueue佇列中刪除。這時候就需要再次通過wake_up重新新增到 runqueue佇列中。
如此反覆,直到condition為真的時候被wake_up.
include/linux/wait.h
wake_up_interruptible(&read_queue_head); //include/linux/wait.h
__wake_up(&read_queue_head, task_interruptible, 1, null) //sched/wait.c
//kernel/sched/core.c
__wake_up_common(&read_queue_head, task_interruptible, nr_exclusive, 0, null); //sched/wait.c
list_for_each_entry_safe(curr, next, &read_queue_head->task_list, task_list)
linux 等待佇列
linux 核心的等待佇列是以雙迴圈鍊錶為基礎資料結構,與程序排程機制緊密結合,能夠用於實現核心的非同步事件通知機制。在這個鍊錶中,有兩種資料結構 等待佇列頭 wait queue head t 和等待佇列項 wait queue t 等待佇列頭和等待佇列項中都包含乙個 list head 型別的域...
linux 等待佇列
linux 核心的等待佇列是以雙迴圈鍊錶為基礎資料結構,與程序排程機制緊密結合,能夠用於實現核心的非同步事件通知機制。在這個鍊錶中,有兩種資料結構 等待佇列頭 wait queue head t 和等待佇列項 wait queue t 等待佇列頭和等待佇列項中都包含乙個 list head 型別的域...
Linux 等待佇列
在閱讀tun驅動時看到,有一些類似 add wait queue 的函式,這些函式正是執行等待佇列的相關操作,要說等待佇列還得從核心程序排程說起,核心排程系統內程序,分配時間片,但是有些程序如從網絡卡中讀資料,在 網絡卡有資料到達之前程序處於阻塞狀態,如果此時給相應程序分配時間片做排程,無疑是浪費系...