wait_event_interruptible() and wake_up()

来源:互联网 发布:儿童k歌软件 编辑:程序博客网 时间:2024/05/16 12:27
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一下就立刻会重新进入运行调度。


/* wait_event_interruptible  宏 */    
#define wait_event_interruptible(wq, condition)    \  
({                                                 \  
      int __ret = 0;                                  \  
      if (!(condition))                               \  
       __wait_event_interruptible(wq, condition, __ret); \  
       __ret;                                         \  
})  
      
当进程执行(进入)wait_event_interruptible宏时,首先检查一遍condition是否为真,如果为真,直接跳出wait_event_interruptible 宏,继续向下执行。 
  
当condition为假时,进入__wait_event_interruptible: 
  
/* __wait_event_interruptible 宏 */ 
#define __wait_event_interruptible(wq, condition, ret)      \  
do {                                                        \  
      DEFINE_WAIT(__wait);                                    \  
      for (;;) {                                              \  
          prepare_to_wait(&wq, &__wait, TASK_INTERRUPTIBLE); \  
          if (condition)                                      \  
              break;                                          \  
          if (!signal_pending(current)) {                     \  
              schedule();                                     \  
              continue;                                       \  
          }                                                   \  
          ret = -ERESTARTSYS;                                 \  
          break;                                              \  
      }                                                       \  
      finish_wait(&wq, &__wait);                              \  
} while (0)  
一,进入__wait_event_interruptible后,首先定义并初始化一个wait_queue_t变量__wait,其中数据为当前进程current,并把__wait入队。接着进入for死循环中: 
在for循环中,__wait_event_interruptible将本进程置为可中断的挂起状态,之后检查condition,如果condition为真,跳出for循环,执行finish_wait,之后跳出wait_event_interruptible。进程继续向下执行。 
二,如果进入for循环后,第一次检查condition为假时, 
进入第二个if语句,调用schedule,将位于TASK_INTERRUPTIBLE状态的当前进程从runqueue  
队列中删除,而从runqueue队列中删除的结果是,当前这个进程将不再参  
与调度,然后进程就停在这了!等待唤醒,即等待调用wake_up。如果不在其他函数内(中断处理程序)调用wake_up,那当前进程就死在这了
如果中断处理程序中调用wake_up(将这个进程重新放入这个runqueue队列中),那当前进程就等待被调度,被调度之后,即执行continue。继续for循环。