轉(zhuǎn)自:http://blog.csdn.net/allen6268198/article/details/8112551 1. 關(guān)于 wait_event_interruptible() 和 wake_up()的使用 讀一下wait_event_interruptible()的源碼,不難發(fā)現(xiàn)這個函數(shù)先將 當(dāng)前進程的狀態(tài)設(shè)置成TASK_INTERRUPTIBLE,然后調(diào)用schedule(), 而schedule()會將位于TASK_INTERRUPTIBLE狀態(tài)的當(dāng)前進程從runqueue 隊列中刪除。從runqueue隊列中刪除的結(jié)果是,當(dāng)前這個進程將不再參 與調(diào)度,除非通過其他函數(shù)將這個進程重新放入這個runqueue隊列中, 這就是wake_up()的作用了。 由于這一段代碼位于一個由condition控制的for(;;)循環(huán)中,所以當(dāng)由 shedule()返回時(當(dāng)然是被wake_up之后,通過其他進程的schedule()而 再次調(diào)度本進程),如果條件condition不滿足,本進程將自動再次被設(shè) 置為TASK_INTERRUPTIBLE狀態(tài),接下來執(zhí)行schedule()的結(jié)果是再次被 從runqueue隊列中刪除。這時候就需要再次通過wake_up重新添加到 runqueue隊列中。 如此反復(fù),直到condition為真的時候被wake_up. 可見,成功地喚醒一個被wait_event_interruptible()的進程,需要滿足: 在 1)condition為真的前提下,2) 調(diào)用wake_up()。 所以,如果你僅僅修改condition,那么只是滿足其中一個條件,這個時候, 被wait_event_interruptible()起來的進程尚未位于runqueue隊列中,因 此不會被 schedule。這個時候只要wake_up一下就立刻會重新進入運行調(diào)度。 2. 關(guān)于wait_event_interruptible的返回值 根據(jù) wait_event_interruptible 的宏定義知: 1) 條件condition為真時調(diào)用這個函數(shù)將直接返回0,而當(dāng)前進程不會 被 wait_event_interruptible和從runqueue隊列中刪除。 2) 如果要被wait_event_interruptible的當(dāng)前進程有nonblocked pending signals, 那么會直接返回-ERESTARTSYS(i.e. -512),當(dāng)前進程不會 被wait_event_interruptible 和從runqueue隊列中刪除。 3) 其他情況下,當(dāng)前進程會被正常的wait_event_interruptible,并從 runqueue隊列中刪除,進入TASK_INTERRUPTIBLE狀態(tài)退出運行調(diào)度, 直到再次被喚醒加入runqueue隊列中后而參與調(diào)度,將正常返回0。 附1:wait_event_interruptible 宏 #define wait_event_interruptible(wq, condition) \ ({ \ int __ret = 0; \ if (!(condition)) \ __wait_event_interruptible(wq, condition, __ret); \ __ret; \ }) 注: C語言中{a,b, ..., x}的的值等于最后一項,即x,因此上述 宏的值是 __ret。 附2:wait_event_interruptible()和 wake_up的等效代碼 wait_event_interruptible(wq, condition) /*等效沒有考慮返回值*/ { if (!(condition)) { wait_queue_t _ _wait; init_waitqueue_entry(&_ _wait, current); add_wait_queue(&wq, &_ _wait); for (;;) { set_current_state(TASK_INTERRUPTIBLE); if (condition) break; schedule(); /* implicit call: del_from_runqueue(current)*/ } current->state = TASK_RUNNING; remove_wait_queue(&wq, &_ _wait); } } void wake_up(wait_queue_head_t *q) { struct list_head *tmp; wait_queue_t *curr; list_for_each(tmp, &q->task_list) { curr = list_entry(tmp, wait_queue_t, task_list); wake_up_process(curr->task); /* implicit call: add_to_runqueue(curr->task);*/ if (curr->flags) break; } } |
|