同期の例
次の例は、ミニドライバーが同期に関して何を行う必要があるかを示しており、同期を使用すべきでない場合の例も含まれています。
例 1: ISR が機能しているミニドライバー
ストリーム クラスの同期が有効になっている場合、すべてのミニドライバー エントリ ポイントは、KeSynchronizeExecutionを使用して、発生した IRQL で呼び出されます。これは、ミニドライバーがコードを実行するときに、アダプターの IRQ レベルと下位 IRQ レベルがすべてマスクされることを意味します。 したがって、ミニドライバーは、このモードでは少量の作業のみを行うことが不可欠です。
ミニドライバーは、通常、発生した IRQL で 10 ~ 20 マイクロ秒を超えるコードを実行すべきではありません。 stream.sysのデバッグ ビルドを使用する場合、ストリーム クラスは、発生した IRQL で費やされた時間をログに記録し、ドライバーがそこに費やしている時間が多すぎる場合にアサートします。 ミニドライバーは、単に要求のハードウェア DMA レジスタをプログラミングする必要がある場合、または ISR のポートを読み取る必要がある場合は、通常、発生した IRQL ですべての処理を実行できます。
ミニドライバーが、PIO 経由でデータを転送するミニドライバーなど、数マイクロ秒を超える処理を行う必要がある場合、ミニドライバーはStreamClassCallAtNewPriorityを使用して、DISPATCH_LEVELコールバックをスケジュールする必要があります。 コールバックでは、ミニドライバーの処理には最大で約 1/2 ~ 1 ミリ秒かかる場合があります。 このモードでは、DISPATCH_LEVELコールバックが ISR と同期されないことに注意する必要があります。
この同期の欠如は、ミニドライバーがコールバック中および ISR 内のリソース (ポートやキューなど) にアクセスするときにハードウェアが安定したままである場合は問題になりません。 ただし、不安定性が問題になる可能性がある場合、ミニドライバーは StreamClassCallAtNewPriority を使用して、DISPATCH_LEVEL コールバックが ISR で使用されるリソースと共有されているリソースに触れる高優先度コールバックをスケジュールする必要があります。
高優先度コールバックは、KeSynchronizeExecution の呼び出しと同じであることに注意してください。 KeSynchronizeExecution では、ミニドライバーは StreamClassCallAtNewPriority では参照しないいくつかのパラメータを参照する必要がありますが、一般的にこの 2 つは同じ動作になります。
ミニドライバーが 1/2 ~ 1 ミリ秒を超えるコードを実行する必要がある場合や、場合によってはPASSIVE_LEVELでサービスを呼び出す必要がある場合 (初期化時など)、StreamClassCallAtNewPriority を低優先度に設定すると、PASSIVE_LEVELワーカー スレッドを取得できます。 低優先度コールバックは何とも同期されず、ミニドライバーが新しい要求 (ReadyForNextRequest NotificationType パラメーターが保留中であると仮定) または低優先度コールバックの実行時に ISR 呼び出しを受け取る可能性があることに注意してください。
例 2: ISR のないミニドライバー
ストリーム クラスの同期が有効になっている場合、ミニドライバーのエントリ ポイントはすべてDISPATCH_LEVELで呼び出されます。 ミニドライバーは、優先度を調整することなく、最大約 1/2 ~ 1 ミリ秒の処理を実行できます。 ミニドライバーが 1/2 ~ 1 ミリ秒を超えるコードを実行する必要がある場合や、場合によってはPASSIVE_LEVELでサービスを呼び出す必要がある場合 (初期化時など)、StreamClassCallAtNewPriority を低優先度に設定すると、PASSIVE_LEVELワーカー スレッドを取得できます。 低優先度コールバックは何とも同期されず、ミニドライバーが新しい要求 (ReadyForNextRequest NotificationType パラメーターが保留中であると仮定) を、低優先度コールバックの実行時に受け取る可能性があることに注意してください。
Stream クラスの同期が必要な場合 使用しない
ストリーム クラスの同期を使用しない状況の例を次に示します。 これには以下が含まれます。
ドライバーが頻繁に (ミニドライバーが受信する要求の約 20% を超える) 1 ミリ秒を超える処理を行う必要がある場合、または Microsoft DirectDraw サービスなどのPASSIVE_LEVEL サービスを頻繁に呼び出す必要がある場合。 stream.sys のデバッグ バージョンを使用する場合、ストリーム クラスはこれらの両方のケースをアサートし、同期が有効になっている状態で検出された場合は停止します。
ミニドライバーが、ハードウェアが関連付けられていないフィルターである場合。 このようなミニドライバーは、同期する基になるハードウェアがなく、ミニドライバーは通常多くの処理を行うので、PASSIVE_LEVELで実行する必要があります。 この場合、ストリーム クラスの同期を使用してオーバーヘッドを無駄にするよりも、独自の同期を行う方が簡単です。 必要に応じて、ミューテックスを使用してキューを保護します。
多くの場合、同期コードのバグは発見が難しいことが多く、特定の環境 (マルチプロセッサ システムで実行されている NT ベースのオペレーティング システムなど) では、何時間も負荷をかけた後で初めてバグが現れることもあります。 ベンダーとの経験に基づけば、こうしたことはほとんどのベンダーにはデバッグする能力も意欲もありません。 完全に非同期の WDM デバイス ドライバーの記述に慣れているドライバー ライターのみが、独自の同期を試みる必要があります。
ミニドライバーがバスオンバス型ドライバー (USB や 1394 周辺機器ドライバーなど) の場合、実際のハードウェアの同期は気にせず、PASSIVE_LEVELで次のレイヤーに要求を呼び出すだけで、通常は DISPATCH_LEVEL でコールバックを受け取ります。