wait_event和wake_up之间的竞争条件

时间:2012-06-13 09:54:04

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

我有一个想要向用户发送状态更改通知的驱动程序。在当前的实现中,它使用proc文件系统来执行此操作。读取过程围绕proc文件系统read()循环。 read() wait_event_interruptible()阻塞write_new_data(),直到内核获得中断,导致call wake_up_interruptible()函数转移到static int flag=0; DECLARE_WAIT_QUEUE_HEAD(info_wq); //user process call read() on /proc/myfile to get to this function int my_proc_read (struct file *filp, char *buf, size_t count, loff_t *pos) { wait_event_interruptible(info_wq, flag != 0); flag = 0; //copy buffers to user return 0; } //when an interrupt comes it schedules this function on the systems' work queue void write_new_data () { //fill buffer with data flag = 1; wake_up_interruptible(&info_wq); } 。这是基本代码(删除了所有不需要的混乱):

read()

现在考虑以下流程:

  1. 用户进程调用write_new_data(),然后等待。
  2. 发生
  3. 中断 - >调用wake_up_interruptible()。写入数据并调用read()
  4. write_new_data()被唤醒,读取数据但进程未重新运行读取(未安排 运行,由于下一次中断没有达到它...)。
  5. 发生
  6. 中断 - >再次触发wake_up_interruptible(),调用{{1}},但没有等待的线程等待...
  7. 进程调用read和blocks。
  8. 注意:这一切都发生在单处理器系统上。此外,只有一个线程读取和一个线程写入新数据。

    如何避免错过第二个中断? (一种解决方案是使用netlink套接字,但我想知道是否有办法在/ proc land中进行)

2 个答案:

答案 0 :(得分:4)

Dan,这是wait_event_interruptible的代码:

#define wait_event_interruptible(wq, condition)             \
({                                  \
    int __ret = 0;                          \
    if (!(condition))                       \
        __wait_event_interruptible(wq, condition, __ret);   \
    __ret;                              \
})

如果在“if(!(condition))”和“__wait_event_interruptible”之间发生中断,则会发生休眠,读取过程将被阻塞,直到发生另一个中断。

答案 1 :(得分:2)

由于在调用wait_event_interruptibleflag = 0之间可能会发生中断,因此会以不受欢迎的方式影响flag变量。

请注意,即使在UP计算机上,内核也可能是抢占式的,具体取决于配置,因此该代码会受到影响。

另外,我建议不要使用简单的'int'标志。相反,您应该使用atomic_tatomic_dec/inc_*操作。请参阅内核中的完成实现,它与您在此处执行的操作类似。

关于问题本身:

如果您查看wait_event_interruptible的代码,您会看到如果条件为真则不会发生睡眠 - 所以您的问题不是问题。