DPC ルーチンの記述に関するガイドライン
DpcForIsr ルーチンまたは CustomDpc ルーチンを記述するときは、以下の点に注意してください。
DpcForIsr または CustomDpc ルーチンは、同じデバイスまたはメモリの場所にアクセスするドライバーの他のルーチンを使用して、物理デバイス、およびドライバーが保持する共有状態情報またはリソースへのアクセスを同期する必要があります。
DpcForIsr または CustomDpc ルーチンは、デバイスまたは状態を ISR と共有する場合、デバイスをプログラムするか、共有状態にアクセスするドライバー指定の SynchCritSection ルーチンのアドレスを指定して、KeSynchronizeExecution を呼び出す必要があります。 詳細については、「クリティカル セクションの使用」を参照してください。
DpcForIsr または CustomDpc ルーチンは、ISR 以外のルーチンと状態またはリソース (インターロックされたキューやタイマー オブジェクトなど) を共有する場合、ドライバーによって初期化されたエグゼクティブ スピン ロックを使用して共有状態またはリソースを保護する必要があります。 詳細については、「スピン ロック」を参照してください。
DpcForIsr ルーチンと CustomDpc ルーチンは、IRQL = DISPATCH_LEVEL で実行されます。これにより、呼び出すことができるサポート ルーチンのセットが制限されます。
たとえば、DpcForIsr ルーチンと CustomDpc ルーチンは、ページング可能なメモリにアクセスすることも割り当てることもできず、カーネル ディスパッチャー オブジェクトがシグナル状態に設定されるのを待つことはできません。 一方、KeAcquireSpinLockAtDpcLevel と KeReleaseSpinLockFromDpcLevel を使用してドライバーのエグゼクティブ スピン ロックを取得および解放することができます。これは、KeAcquireSpinLock と KeReleaseSpinLock よりも高速に実行されます。
DPC ルーチンはブロック呼び出しを行うことはできませんが、PASSIVE_LEVEL と同じ IRQL で実行されるシステム ワーカー スレッドで実行される作業項目をキューに登録できます。 作業項目は、ディスパッチャー オブジェクトを待機するブロッキング呼び出しを行うことができます。 作業項目をキューに入れるため、DpcForIsr ルーチンは通常、IoQueueWorkItem などのルーチンを呼び出し、CustomDpc ルーチンは通常 ExQueueWorkItem ルーチンを呼び出します。
DpcForIsr ルーチンと CustomDpc ルーチンは通常、デバイスで次の I/O 操作を開始する役割を担います。
直接 I/O を使用する最下位レベルの物理デバイス ドライバーの場合、この責任には、SynchCritSection ルーチンを使用して、ドライバーが IoStartNextPacket を呼び出す前に現在の IRP を満たすためにより多くのデータを転送するようデバイスをプログラムすることが含まれます。
DpcForIsr ルーチンと CustomDpc ルーチンは、短時間だけ実行する必要があり、ワーカー スレッドにできるだけ多くの処理を委任する必要があります。
DPC ルーチンはプロセッサ上で実行されますが、すべてのスレッドが同じプロセッサで実行されなくことはなくなります。 キューに入れられ、実行する準備ができている他の DPC ルーチンは、現在の DPC ルーチンが完了するまで実行をブロックできます。 システムの応答性の低下を回避するため、一般的な DPC ルーチンは、呼び出されるたびに 100 マイクロ秒以下で実行する必要があります。 タスクが 100 マイクロ秒を超える必要があり、DISPATCH_LEVEL と同じ IRQL で実行する必要がある場合、DPC ルーチンは 100 マイクロ秒後に終了し、後でタスクが完了されるように 1 つ以上 の CustomTimerDpc ルーチンをスケジュールする必要があります。 CustomTimerDpc ルーチンについて詳しくは、「タイマー オブジェクトと DPC」をご覧ください。
DPC ルーチンは、DISPATCH_LEVEL で実行する必要があるタスクのみ実行し、IRQL = PASSIVE_LEVEL で実行されるスレッドに残りの割り込み関連作業を委任する必要があります。 たとえば、DPC ルーチンは、システム ワーカー スレッドで実行する作業項目をキューに登録できます。
KeStallExecutionProcessor ルーチンを呼び出して実行を遅延させる DPC ルーチンは、100 マイクロ秒を超える遅延を指定してはなりません。
WDK のパフォーマンス分析ツールを使用して、DPC ルーチンの実行時間を評価します。 Tracelog ツールを使用して DPC の実行時間を監視する例については、「例 15: DPC/ISR 時間の測定」をご覧ください。
ドライバーが DMA を使用し、その AdapterControl ルーチンが KeepObject または DeallocateObjectKeepRegisters を返す場合 (これにより、追加の転送操作のためにシステム DMA コントローラー チャネルまたはバス マスター アダプターが保持されます)、DpcForIsr ルーチンまたは CustomDpc ルーチンは、現在の IRP を完了し、コントロールを返す前に、FreeAdapterChannel または FreeMapRegisters を使用してアダプター オブジェクトまたはマップ レジスタを解放する必要があります。
最下位レベルの物理デバイス ドライバーが、コントローラーを通じて接続されたデバイスに I/O 操作を同期するようコントローラー オブジェクトを設定した場合、その DpcForIsr または CustomDpc ルーチンは、現在の IRP を完了してコントロールを返す前に、IoFreeController を使用してコントローラー オブジェクトを解放します。
DpcForIsr ルーチンと CustomDpc ルーチンは通常、特定の要求の処理時に発生したデバイス エラーをログに記録して、必要に応じて現在の要求を再試行し、I/O ステータス ブロックを設定して、現在の IRP の IoCompleteRequest を呼び出す必要があります。
ドライバーとデバイスで重複した I/O 操作がサポートされている場合、ドライバーは重複した I/O 操作を処理するための規則に従う必要があります。
通常、ドライバーの DpcForIsr ルーチンまたは CustomDpc ルーチンは、ドライバーがサポートする必要があるパブリック I/O コントロール コードのサブセットに対してのみ I/O 処理を完了します。 特に、DPC ルーチンは、次の特性を持つデバイス制御要求の操作を完了します。
物理デバイスの状態を変更する要求
物理デバイスに関する本質的に揮発性の情報を返す必要がある要求