1
votes

I have a device driver where the hardware is constantly streaming data into a circular buffer in kernel space. When the user calls read(), data is moved from this buffer to the caller's buffer. An interrupt fires if the hardware fills a DMA descriptor (i.e., more data is ready) or if the hardware encountered an error. In either case, the interrupt handler schedules work to be done in the bottom half.

The bottom half figures out if the interrupt was caused by a hardware failure or data becoming available. In either case it sets some flags to let the read() syscall know what happened. After setting said flags, the bottom half calls wake_up_interruptible(&my_waitqueue);

In the read() syscall, I want to block for some timeout if there is not data available in the kernel buffer. If the timeout expires, I just let the caller know that data isn't available. As a result, I call wait_event_interruptible_hrtimeout(my_waitqueue, (error || data_ready), my_timeout); Basically, I block waiting for either an error condition or data becoming available.

My question pertains to whether or not the ordering of these threads (i.e., the bottom half and the read() call) matters. Particularly, I am wondering if wait_event_interruptible_hrtimeout() always waits for someone to wake it up? What if there was a previous call to wake_up_interruptible()?

Said differently, I am concerned with the following scenario:

  1. Interrupt fires due to hardware failure. Remember that transfers to the circular buffer occur independently with regards to the read() syscall.
  2. Bottom half runs, flags the transfer as failed and calls wake_up_interruptible(). Note that since this is a hardware failure, no more interrupts will fire and we won't run the bottom half again until the device is reset.
  3. User process wants more data, and calls read(). We now hit the line of code containing wait_event_interruptible_hrtimeout(). Do we block waiting to be woken up or does the wait queue know about the previous call to wake_up_interruptible()?

Basically I am wondering if I need to first check the condition I passed into wait_event_interruptible_hrtimeout() (i.e., (error || data_ready)) before calling wait_event_interruptible_hrtimeout().

1
Consider adding some (pseudo) code to help visualise your description. That way the phrasing "bottom half" would for example become easier to process.Yunnosch
"Do we block waiting to be woken up or does the wait queue know about the previous call to wake_up_interruptible()?" - wake_up functions calls never affect on futher waitings. "if I need to first check the condition" - Condition is checked inside wait_event macro even before the first attempt to wait.Tsyvarev

1 Answers

0
votes

Thanks to Tsyvarev, I decided to poke around the kernel source code some more.

Here is what I found:

#define wait_event_interruptible_hrtimeout(wq, condition, timeout)  \
({                                                                  \
    long __ret = 0;                                                 \
    might_sleep();                                                  \
    if (!(condition))                                               \
        __ret = __wait_event_hrtimeout(wq, condition, timeout,      \
                                       TASK_INTERRUPTIBLE);         \
    __ret;                                                          \
})

The condition is checked for first, which means that if I get data or a hardware failure occurred, I will not block since that's the condition I pass into this function.