カーネルモジュールの共有メモリについて誤った仮定をしていますか?

カーネルモジュールの共有メモリについて誤った仮定をしていますか?

私は「デバイスドライバ」を書いています(ここでソースコードを参照してください:https://bitbucket.org/wothke/websid/src/master/raspi/websid_module/)はほとんどの場合うまく機能します(参照:https://www.youtube.com/watch?v=bE6nSTT_038) しかし、時々、デバイスがランダムに衝突する可能性があります。

「デバイスドライバ」は、いくつかのGPIOピンを介して接続されているいくつかのオーディオチップを制御する簡単ですが、タイミングが重要な再生ループを実行するkスレッドを起動します。このkthreadは、通常のカーネル使用からほとんど除外する必要がある「分離された」CPUコア(kthread_bindを使用)で実行されます(以下のカーネル構成の詳細を参照)。 sched_set_fifoを介してkthreadに高い優先順位を与えます。 kthreadはサブルーチン呼び出しを実行せず、以前にカーネルに割り当てられていなかったメモリを必要としません。 (スレッドはget_cpu、local_irq_save、local_bh_disableを使用してタイミングを妨げる可能性があるすべてを一時的に無効にします。 . 使用される。)

通常の「Raspberry OS」「Desktop」カーネルをコンパイルしましたが、特にNO_HZ_FULL(例:「Full Dynamic System(No Tick)」)を有効にしました。また、cmdline.txtを介してコア#3を具体的に分離しました:isolcpus = 3 rcu_nocbs = 3 rcu_nocb_poll = 3 nohz_full = 3は、次のようにする必要があります。

最も一般的な容疑者は、おそらく、前述の「再生」kthreadと「ユーザー空間」のデータコンストラクタ間のすべての通信に使用される「共有カーネルメモリ」バッファです。私は潜在的な競争条件を避けるために私が考えることができるすべての予防措置を講じましたが、おそらくある種のCPUキャッシュ効果があるか、私が見落としている他のものがあるかもしれません。 「共有バッファ」には、このように設定/使用される4つのページ整列領域が含まれています。しなければならない安全な通信/同期化を保証します。

  1. 最初のページには、u32またはuint32_t(デフォルトではアトミックでなければならない)としてアクセスできる32ビットフラグのみが含まれています。 kthreadはこのフラグが0の場合にのみ更新し、ゼロ以外の値にのみ設定します。 Userlandコードはこのフラグをゼロにリセットし、ゼロ以外の値がある場合にのみkthreadによって設定されたゼロ以外の値を受け取ったことを受け入れます。

  2. 2 番目のページには 1) と同様のフラグが含まれていますが、反対方向です。つまり、kthread は「userland」からゼロ以外のコンテンツを受け取ります。

  3. 次に、3番目(+後続)ページには、単純なデュアルバッファリングシナリオのための最初のバッファが含まれます。このバッファは "userland"プロデューサによってのみ作成され、kthreadからのみ読み込まれます。 2つのフラグによって実装された「ping / pong」プロトコルは、バッファが同時に「決して」使用されないように設計されています。 kthreadはバッファの1つがいっぱいになる可能性があることを示す信号を送信してシーケンスを開始し、次に「userland」信号がそれを返します。対応するバッファの充填を完了します。つまり、ktheadはプロデューサからのシグナルを見た後にのみバッファから読み込みを開始します(これを行うことは安全です)共有メモリ領域のどの部分が更新されたかを報告します。

  4. これにより、n番目(+)ページには2番目のバッファが含まれます((3)で指定されているすべての内容がここにも適用されます)。

しかし、上記の問題が発生しても、kthreadまたはそのユーザーモードプロセスをブロックできます。しかし、なぜこれがシステム全体に衝突を引き起こすのかわかりません。

私にとって最も論理的な説明は、「共有バッファ」がランダムに再配置され(したがってランダムなメモリ破損が発生する場合)、しかし、以下を通じて割り当てられたバッファではこのようなことが発生してはならないと思います。

_raw_buffer = kmalloc(AREA_SIZE + 2*PAGE_SIZE, 
                GFP_KERNEL & ~__GFP_RECLAIM & ~__GFP_MOVABLE);

または、コア#3で何かを待つことを特別にブロックするいくつかのカーネル機能がある場合(私のkthreadがそのCPUの他のすべてを捕まえるので、これは起こりません...)。何が起こるのか驚くでしょう。問題は常にマシンをクラッシュさせるのではなく、時々発生します。

どんなアイデアがありますか?

ベストアンサー1

コードのすべての合理的なポイントに「メモリバリア」を追加しても、状況が改善されていない後に最終的に動作する解決策を見つけました。問題は共有メモリとまったく関係がないようです。代わりに、スケジューラによってトリガされるように見え、長期実行kthreadに "schedule()"の呼び出しを追加すると、システムがハングするのを防ぐようです。

残念ながら、この回避策は私にとって実行可能な解決策ではありませんでした。Schedule() を呼び出さずに長期実行kthreadを使用する方法はありますか?

おすすめ記事