等待佇列,poll

2021-09-27 07:16:26 字數 3783 閱讀 7321

原文**:等待佇列,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 的函式,這些函式正是執行等待佇列的相關操作,要說等待佇列還得從核心程序排程說起,核心排程系統內程序,分配時間片,但是有些程序如從網絡卡中讀資料,在 網絡卡有資料到達之前程序處於阻塞狀態,如果此時給相應程序分配時間片做排程,無疑是浪費系...