プリエンプティブな Linux 3.0 カーネルを搭載した Android 組み込みプラットフォーム (Exynos5dual ベース) での wait_event と wake_up の奇妙な動作について質問があります。非プリエンプティブ カーネル (すべてのバージョン) を使用する通常の SMP ラップトップでは発生しません。
従来のスリーパー/ウェイカー シナリオの Linux デバイス ドライバーがあり、次のようになります。
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
フラグのすべての読み取りと書き込みはアトミックであり、アトミック bitops (カーネル セット/テスト ビット) から揮発性の atom_t まで、atomic_t vars を使用した各読み取り/書き込み用のメモリ バリアの使用に移行しました (これによると)。
TaskA が実際に待機を開始した場合 (wait_event_* カーネル関数が最初に条件をチェックするため、常にそうであるとは限りません)、フラグの値が変更され、wake_up() が呼び出されたときに taskB によってウェイクアップされるのではなく、完全なタイムアウトを待機します。
2 つのタスクが異なるコアで発生していると思われます。Core1 は、wait_event_..() の後にディープ スリープし、Core2 で発生する wake_up_interruptible() によってウェイクアップできません。
これが本当なのか、それとも他の何かが原因なのか、誰か知っていますか?
注: スリーパーのタスク構造体 ptr を保存してから、wake_up_interruptible() の前に (およびそれに加えて) wake_up_process (saved_ptr) を実行すると、この問題は解決するようです。これは最適とは言えず、もっと良い方法はないかと考えています。