Code for Wait_Event_Interruptible

code for wait_event_interruptible

It's in include/linux/wait.h:

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

...

#define __wait_event_interruptible(wq, condition, ret)        \
do { \
DEFINE_WAIT(__wait); \
\
for (;;) { \
prepare_to_wait(&wq, &__wait, TASK_INTERRUPTIBLE); \
if (condition) \
break; \
if (!signal_pending(current)) { \
schedule(); \
continue; \
} \
ret = -ERESTARTSYS; \
break; \
} \
finish_wait(&wq, &__wait); \
} while (0)

Wait_event_interruptible Vs wake_up_interruptible

  1. When the condition is already true, there is no need to wait.

    (The wait_event* functions check the condition also before they begin the actual wait.)
  2. When the condition is still false, it will go back to sleep.

race condition between wait_event and wake_up

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.

From sleep_on() to wait_event()?

You may define sleep_on function as it has been defined in pre-3.15 kernels. Like this:

void
sleep_on(wait_queue_head_t *q)
{
unsigned long flags;
wait_queue_t wait;

init_waitqueue_entry(&wait, current);

__set_current_state(TASK_UNINTERRUPTIBLE);

spin_lock_irqsave(&q->lock, flags);
__add_wait_queue(q, &wait);
spin_unlock(&q->lock);
schedule();
spin_lock_irq(&q->lock);
__remove_wait_queue(q, &wait);
spin_unlock_irqrestore(&q->lock, flags);
}

(originated from the code of sleep_on_common but with timeout things removed.)

For those who want to see the original code on kernel.org, see sleep_on_common() with commit 32d01dc7be4e725ab85ce1d74e8f4adc02ad68dd in April 2014 (a few days before the function was removed).


As for wait_event() and friends, using constant condition is wrong:

  • 'true' will never sleep
  • 'false' will never woken up


Related Topics



Leave a reply



Submit