为什么在prepare_to_wait之后必须检查wait_event中的条件?

时间:2015-08-28 06:18:34

标签: linux-kernel linux-device-driver blockingqueue

我试图了解在linux内核中如何实现wait_event。 ldd3中有一个代码示例,其中使用prepare_to_wait(http://www.makelinux.net/ldd3/chp-6-sect-2)解释内部实现。

static int scull_getwritespace(struct scull_pipe *dev, struct file *filp)
{
    while (spacefree(dev) == 0) {
        DEFINE_WAIT(wait);

        up(&dev->sem);
        if (filp->f_flags & O_NONBLOCK)
            return -EAGAIN;
        PDEBUG("\"%s\" writing: going to sleep\n",current->comm);
        prepare_to_wait(&dev->outq, &wait, TASK_INTERRUPTIBLE);
        if (spacefree(dev) == 0)  // Why is this check necessary ??
            schedule(  );
        finish_wait(&dev->outq, &wait);
        if (signal_pending(current))
            return -ERESTARTSYS; /* signal: tell the fs layer to handle it */
        if (down_interruptible(&dev->sem))
            return -ERESTARTSYS;
    }
    return 0;
}

在书中,解释如下。

  

然后是对缓冲区的强制检查;我们必须处理此案   我们输入后缓冲区中的空间可用   while循环(并删除信号量)但在我们自己之前   进入等待队列。没有那个检查,如果读者进程是   能够在那个时间完全清空缓冲区,我们可能会错过   只有醒来,我们永远都会得到并永远沉睡。满意了   我们必须睡觉,我们可以打电话给我们。

我无法理解这条解释。如果在调用schedule()之前未完成if (spacefree(dev) == 0),我们将如何进入无限期睡眠状态? 如果此强制性检查不存在,则wakeup()仍会将进程状态重置为TASK_RUNNING并按照下一段中的说明安排返回。

  

值得再看一下这种情况:如果唤醒会发生什么   发生在if语句中的测试和调度调用之间?   在那种情况下,一切都很好。唤醒将进程状态重置为   TASK_RUNNING和安排返回 - 虽然不一定马上。   只要测试发生在该过程已经完成之后   等待队列并改变其状态,事情就会奏效。

1 个答案:

答案 0 :(得分:3)

重要的是,在调用 prepare_to_wait()之后完成了(最后一次)检查。

prepare_to_wait()将指向当前进程的指针放入等待队列。如果在<{em> prepare_to_wait()调用之前发生唤醒,则唤醒将无法影响当前进程。