Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does wait queue implementation wait on a loop until condition is met?

Lets consider a single processor scenario.

wait_event_interruptible() (or other wait APIs) wait in a loop until a certain condition is met.

Now, since linux has threads implemented as separate processes, I believe a false wake (where the wait_event* is woken up with the condition not met) is indicative of error in the program/driver.

Am I wrong? - Is there any valid scenario where such false wakes can happen and are used? In other words, why wait on the condition in a loop in wait_event* implementation?

like image 323
Chethan Avatar asked Oct 18 '25 19:10

Chethan


2 Answers

A common use case for wait queues is with interrupts. Perhaps your kernel driver is currently waiting on three different conditions, each of which will be awoken with an interrupt.

This allows your kernel interrupt handler to just wake up all of the listeners, who can then determine among themselves if their particular condition has occurred, or if they should wake up.

Also, you can get spurious interrupts because interrupts can be shared and because of interrupts being deferred and coalesced.


Adding some code and what not to try to be more explicit.

I've written some code below that could be part of a kernel driver. The interrupt handler is simply going to wake up all of the listeners. However, not all of the listeners may actually be done. Both will be woken up by the same interrupt, but they will both look to see if their particular condition is done before continuing.

// Registered interrupt handler
static irqreturn_t interrupt_handler(void *private) {
    struct device_handle *handle = private;
    wake_up_all(&handle->wait);
}

// Some Kernel Thread
void program_a(struct device_handle * handle) {
    wait_event_interruptible(&handle->wait, hardware_register & 0x1);
    printk("program_a finished\n");
}

// Some other kernel thread
void program_b(struct device_handle * handle) {
    wait_event_interruptible(&handle->wait, hardware_register & 0x2);
    printk("program_b finished\n");
}
like image 71
Bill Lynch Avatar answered Oct 20 '25 14:10

Bill Lynch


Code:

#define __wait_event(wq, condition)                     \
do {                                    \
    DEFINE_WAIT(__wait);                        \
                                    \
    for (;;) {                          \
        prepare_to_wait(&wq, &__wait, TASK_UNINTERRUPTIBLE);    \
        if (condition)                      \
            break;                      \
        schedule();                     \
    }                               \
    finish_wait(&wq, &__wait);                  \
} while (0)

(Besides the fact that the kernel is preemptive...)

I assume you're referring to the infinite 'for' loop above? If so, the main reason it's there is this:

The code does not make any assumption about state once it's awoken. Just being awoken does not mean the event you were waiting upon has actually occurred; you must recheck. That's exactly what the loop achieves. If the 'if' condition comes true (which it should, in the normal case), it exits the loop, else (spurious wakeup) it puts itself to sleep again by calling schedule().

like image 20
kaiwan Avatar answered Oct 20 '25 14:10

kaiwan



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!