あなたがリストしたこれらの3つの要因から、最初の1つだけが実際に正しいです。残りについては—そうではありません。ユーザースペースコードがDMA操作を実行することは可能です—問題ありません。製品にこの手法を採用しているハードウェアアプライアンス企業はたくさんあります。すべてのI/Oが完全なカーネルバイパスで実行されている場合でも、割り込み駆動のユーザースペースアプリケーションを使用することもできます。もちろん、単にmmap()
onを実行するのは簡単ではありません/dev/mem
。
カーネルにドライバーの最小限の部分を含める必要があります。これは、カーネルから必要な最小限のドライバーをユーザースペースに提供するために必要です(考えてみれば、これ/dev/mem
もキャラクターによってバックアップされるためです) 。デバイスドライバ)。
DMAの場合、実際には非常に簡単ですmmap
。要求を処理し、DMAバッファーをユーザースペースにマップするだけです。割り込みの場合—もう少し注意が必要です。割り込みはカーネルによって処理される必要がありますが、カーネルは何の作業も行わず、たとえば、を呼び出すプロセスをウェイクアップするだけepoll_wait()
です。もう1つのアプローチは、DOSEMUによって行われるようにプロセスに信号を配信することですが、これは非常に低速であり、推奨されません。
実際の質問として、考慮すべき要素の1つはリソースの共有です。複数のアプリケーション間でデバイスを共有する必要がなく、ユーザースペースで実行できないことがない限り、ユーザースペースを選択してください。ユーザースペースコードの記述は非常に簡単なので、開発サイクル中におそらく多くの時間を節約できます。ただし、2つ以上のアプリケーションがデバイス(またはそのリソース)を共有する必要がある場合、それを可能にするために膨大な時間を費やす可能性があります。複数のプロセスが同時にフォーク、クラッシュ、(同じ?)メモリをマッピングすることを想像してみてください。結局のところ、IPCは通常カーネルを介して行われるため、アプリケーションが相互に「通信」を開始する必要がある場合は、パフォーマンスが大幅に低下する可能性があります。
もう1つの要素は、カーネルインフラストラクチャです。ネットワークデバイスドライバーを作成するとします。ユーザースペースでそれを行うのは問題ではありません。ただし、これを行う場合は、カーネルに存在するLinuxのデフォルトのスタックを使用できないため、完全なネットワークスタックも作成する必要があります。
可能であればユーザースペースを利用し、それを機能させるための労力はカーネルドライバーを作成するよりも少なくて済みます。また、いつかコードをカーネルに移動する必要があるかもしれないことを念頭に置いてください。実際、これは、マクロが定義されているかどうかに応じて、ユーザースペースとカーネルスペースの両方で同じコードをコンパイルするのが一般的な方法です。ユーザースペースでのテストの方がはるかに快適だからです。