手动将进程置于睡眠状态时是否存在竞争条件

时间:2015-01-19 16:20:10

标签: linux linux-kernel sleep race-condition device-driver

当我阅读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}}之后。

为什么存在这样的差异?

1 个答案:

答案 0 :(得分:2)

来自LDD3第6章:

“通过在设置流程状态后检查我们的条件,我们会受到所有人的保护 可能的事件序列。如果我们等待的条件已经出现 在设置进程状态之前,我们注意到这个检查并没有实际睡眠。如果 此后唤醒发生,无论我们是否拥有,该过程都是可以运行的 实际上还没睡觉。“