i have a question about what seems to be weird behavior of wait_event and wake_up on an Android embedded platform (Exynos5dual based) with a pre-emptive linux 3.0 kernel. It does not happen on a normal SMP laptop with a non-preemptive kernel (any version)
We have a linux device driver with a classic sleeper/waker scenario and here's what happens:
T0: taskA:
if(!flag)
wait_event_interruptible_timeout(wq, flag==true, timeout=0.5sec)
T1: (after a few msec) taskB:
atomic set flag
wake_up_interruptible()
T2: (after timeout msec) taskA:
wait_event_interruptible_timeout expires (ret 0) instead of waking up at T1
All read and writes of flag are atomic, and have gone using from atomic bitops (kernel set/test bit), to volatile atomic_t, to using memory barriers for each read/write with atomic_t vars (according to this)
if TaskA actually starts waiting (wait_event_* kernel functions first check the condition so it may not always be the case), then it waits for the full timeout instead of getting woken up by taskB when the flag changes value and wake_up() is called.
We suspect that the two tasks occur on different cores. Core1 deep-sleeps after wait_event_..() and cannot be woken up by wake_up_interruptible() which occurs on Core2.
Does anyone know if this is true, or if something else is to blame?
NOTE: The issue seems to go away if we save the sleeper's task struct ptr and and then do wake_up_process(saved_ptr) before (and in addition to) wake_up_interruptible(). We find this less than optimal and wonder if there is a better way.