您的位置:首页 > 大数据 > 人工智能

关于函数wait_event_interruptible(wq, condition)

2013-08-17 09:45 323 查看
wait_event_interruptible(wq, condition),该函数修改task的状态为TASK_INTERRUPTIBLE,意味着该进程将不会继续运行直到被唤醒,然后被添加到等待队列wq中。

在wait_event_interruptible()中首先判断condition是不是已经满足,如果条件满足则直接返回0,否则调用__wait_event_interruptible(),并用__ret来存放返回值

#define wait_event_interruptible(wq, condition)          \

({                                                       \

    int __ret = 0;                                       \

    if (!(condition))                                    \

        __wait_event_interruptible(wq, condition, __ret);\

    __ret;                                               \

})

在无限循环中,__wait_event_interruptible()将本进程置为可中断的挂起状态,反复检查condition是否成立,如果成立则退出,如果不成立则继续休眠;条件满足后,即把本进程运行状态置为运行态

,并将__wait从等待队列中清除掉,从而进程能够调度运行。如果进程当前有异步信号(POSIX的),则返回-ERESTARTSYS。

#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)

 

以下是在linux下OV7725驱动(s3c2440camif.c)中的一个例子

定义等待队列

wait_queue_head_t cmdqueue;(s3c2440camif.h中定义的)

初始化等待队列

static int __init camif_probe(struct platform_device *dev)

{

 ......

 pdev->cmdcode = CAMIF_CMD_NONE;

 init_waitqueue_head(&pdev->cmdqueue);

 ......

}

调用等待队列

static int start_capture(struct s3c2440camif_dev * pdev, int stream)

{

 ......

 if (stream == 0)

 {

  pdev->cmdcode = CAMIF_CMD_STOP;

  ret = wait_event_interruptible(pdev->cmdqueue, pdev->cmdcode == CAMIF_CMD_NONE);

 }

 return ret;

 ......

}

在中断处理函数中唤醒等待队列

static irqreturn_t on_camif_irq_c(int irq, void * dev)

{

 ......

 pdev->cmdcode = CAMIF_CMD_NONE;

 wake_up(&pdev->cmdqueue);

 ......

}

static irqreturn_t on_camif_irq_p(int irq, void * dev)

{

 ......

 pdev->cmdcode = CAMIF_CMD_NONE;

 wake_up(&pdev->cmdqueue);

 ......

}

在下面函数中调用start_capture()

static ssize_t camif_read(struct file *file, char __user *data, size_t count, loff_t *ppos)

{

 ......

 if(start_capture(pdev, 0) != 0)

 {

  return -ERESTARTSYS;

 }

 ......

}

******************************************************************************************************************

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。 

读一下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。 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: