【发布时间】:2015-08-28 16:36:34
【问题描述】:
我试图了解在 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) 在调用 schedule() 之前没有完成,我们将如何进入无限期休眠?
如果此强制性检查不存在,wakeup() 仍会将进程状态重置为 TASK_RUNNING 并安排返回,如下一段所述。
这个案例值得再看一遍:如果唤醒会发生什么 在 if 语句中的测试和调度调用之间发生了什么? 在这种情况下,一切都很好。唤醒将进程状态重置为 TASK_RUNNING 和计划返回——尽管不一定马上。 只要测试发生在进程将自身置于 等待队列并更改其状态,一切都会正常。
【问题讨论】:
标签: linux-kernel linux-device-driver blockingqueue