2012-06-13 61 views
2

我有一个驱动程序想要向用户发送有关状态更改的通知。在当前的实现中,它使用proc文件系统来执行此操作。读取过程围绕read()循环到proc文件系统。 read()块与wait_event_interruptible(),直到内核得到一个中断,导致write_new_data()函数call wake_up_interruptible()。这里是基本的代码(去掉所有不需要的杂波):wait_event和wake_up之间的竞争条件

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); 
} 

现在考虑下面的流程:

  1. 用户进程调用read(),然后等待。
  2. 发生中断 - >write_new_data()被调用。写数据并致电wake_up_interruptible()
  3. read()被唤醒,读取数据但进程没有重新运行读取(没有安排 运行,没有得到它,因为下一个中断...)。发生
  4. 中断 - >write_new_data()再次被触发,调用wake_up_interruptible()但没有等待线程正在等待...
  5. 过程调用read和块。

注意:这一切都发生在单处理器系统上。另外只有一个线程读取和一个线程写入新数据。

如何避免丢失第二个中断? (一种解决方案是使用netlink的插座,但我不知道是否有一种方法可以做到这一点在/ proc土地)

+0

是什么样的驱动程序?以及它正在追查什么状态? –

回答

1

由于中断可以调用wait_event_interruptibleflag = 0之间发生,它会影响在该flag变量不想要的方式。

请注意,即使在UP机器上,根据配置,内核可能是抢先式的,并且该代码会因此受到影响。

另外,我建议不要使用简单的'int'标志。相反,您应该使用atomic_tatomic_dec/inc_*操作。在内核中查看完成的实现,它和你在这里做的事情类似。

关于这个问题本身:

如果你会看在wait_event_interruptible的代码,你会发现,如果条件为真,睡眠不会发生 - 所以你的问题是一个非问题。

+0

那么,为了简单起见,我拿出了带自旋锁的代码部分来控制旗子的变化。感谢有关atomic_dec/inc和完成的提示 - 我将详细阅读这些内容。仍然是我的基本问题仍然没有答案... –

+0

你提出的流程有一些不太正确的地方。在第二次中断之后,标志== 1,并且下一次调用'read',即使它被中断延迟了,似乎也无法阻塞,因为由于提供的条件,wait_Event_interruptible将立即退出。 –

+0

这里我们不同意。我的理解是,如果唤醒被调用时,没有线程在等待队列上(不称为wait_event),那么条件为真的事实将无济于事,进程将休眠直到有人再次调用wake_up(并且只有这样条件检查是否正确) –

3

丹,这里是wait_event_interruptible的代码:

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

如果只是之间发生了中断,“如果((条件)!)”和“__wait_event_interruptible”,睡眠会发生和读取过程将直到发生另一个中断为止。

+0

不,看看__wait_event_interrupts() - 它确实如果(条件)break'睡觉前。 –

+0

错字;我的意思是看__wait_event_interruptible()。它再次检查条件。为了进一步阐明 - 即使中断发生在第二次检查后,调用schedule()将立即返回,因为在中断中调用了wake_up。 __wait_event_interruptible在再次检查条件之前调用prepare_to_wait()*的原因是为了防止条件更新上的竞争。因此,API是有效的,但在问题中处理'flag'仍然是一个错误。 –

+0

好的,谢谢丹。 – Adrien