当我阅读ldd3第6章时,我对下面显示的代码感到困惑:
while (spacefree(dev) == 0) { /* full */ 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)
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;
}
if (spacefree(dev) == 0)
和schedule()
之间是否存在争用条件。如果if语句刚刚结束时spacefree(dev)
函数返回非零值,那么该进程可能会失去唯一被唤醒的机会。谁能告诉我这些代码背后的机制是什么?
顺便说一下,我在 Linux内核开发中找到了另一个代码片段,它类似于上面的代码片段。然而,一些细节是不同的。
DEFINE_WAIT(wait);
add_wait_queue(q, &wait);
while (!condition) { /* condition is the event that we are waiting for */
prepare_to_wait(&q, &wait, TASK_INTERRUPTIBLE);
if (signal_pending(current))
/* handle signal */
schedule();
}
finish_wait(&q, &wait);
非常不同的是添加了add_wait_queue()
函数,该函数未出现在第一个代码段中。
第二个区别在于,在第二个代码段的while
语句中,schedule()
之前没有条件测试。为什么呢?
第三个区别是signal_pending()
函数的位置,一个位于schedule()
之前,另一个位于{{1}}之后。
为什么存在这样的差异?
答案 0 :(得分:2)
来自LDD3第6章:
“通过在设置流程状态后检查我们的条件,我们会受到所有人的保护 可能的事件序列。如果我们等待的条件已经出现 在设置进程状态之前,我们注意到这个检查并没有实际睡眠。如果 此后唤醒发生,无论我们是否拥有,该过程都是可以运行的 实际上还没睡觉。“