race condition between wait_event and wake_up

I have a driver that wants to send notification to the user about a status change. In the current implementation it uses the proc filesystem to do so. The read process loops around a read() to the proc filesystem. The read() blocks with wait_event_interruptible() until the kernel gets an interrupt which causes the write_new_data() function to call wake_up_interruptible(). Here's the basic code (removed all unneeded clutter):

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

Now consider the following flow:

  1. User process calls read(), then waits.
  2. interrupt occurs -> write_new_data() is called. writes data and calls wake_up_interruptible().
  3. read() is awaken, reads data but process has not rerun read (wasn't scheduled to run, didn't get to it because of the next interrupt...).
  4. interrupt occurs -> write_new_data() is triggered again, calls wake_up_interruptible() but no waiting thread is waiting...
  5. process calls read and blocks.

Note: this all happens on a uni-processor system. Also there is only one thread reading and one thread writing new data.

How can I avoid missing the second interrupt? (One solution is to use netlink sockets but I was wondering if there is a way to do it in /proc land)

Answers


Since the interrupt can occur between the call to wait_event_interruptible and flag = 0, it would affect the flag variable in an unwanted way.

Note that even on a UP machine, the kernel could be preemptive depending on the configuration, and that code would be affected as a result.

Also, I advice to not use a simple 'int' flag. Instead, you should use atomic_t and atomic_dec/inc_* operations. See the implementation of completions inside the kernel, it does something similar to what you are doing here.

About the question itself:

If you'll look in the code of wait_event_interruptible you'll see that the sleep doesn't take place if the condition is true - so your problem is a non-problem.


Dan, here is the code of wait_event_interruptible :

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

If an interrupt occurs just between "if (!(condition))" and "__wait_event_interruptible", the sleep will take place and the read process will be block untill another interrupt occurs.


Need Your Help

Show as many columns to fit GridView width ASP.NET

c# asp.net gridview

I have a GridView which is populated by images from my database. My current GridView looks like that:

Are there any opencv function like "cvHoughCircles()" for square detection?

c++ image-processing opencv

Are there any opencv function like "cvHoughCircles()" that can use for square detection programming