wait_event_interruptible與wake_up配套使用


1. 關於 wait_event_interruptible() 和 wake_up()的使用 
  
讀一下wait_event_interruptible()的源碼,不難發現這個函數先將 
當前進程的狀態設置成TASK_INTERRUPTIBLE,然後調用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. 
  
可見,成功地喚醒一個被wait_event_interruptible()的進程,需要滿足: 
  
   在 1)condition爲真的前提下,2) 調用wake_up()。 

所以,如果你僅僅修改condition,那麼只是滿足其中一個條件,這個時候, 
被wait_event_interruptible()起來的進程尚未位於runqueue隊列中,因 
此不會被 schedule。這個時候只要wake_up一下就立刻會重新進入運行調度。 
  
2. 關於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。 
  
附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; 
      } 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章