スピン ロック使用中のエラーおよびデッドロックの防止

ドライバー ルーチンは、スピン ロックを保持している間、システムを停止せずにハードウェア例外を発生させることも、ソフトウェア例外を発生させることもできません。 言い換えると、ドライバーの ISR と、ドライバーが KeSynchronizeExecution の呼び出しで提供する SynchCritSection ルーチンは、ページ フォールトや算術例外などの障害やトラップを引き起こすことはできず、ソフトウェア例外を発生させることはできません。 KeAcquireSpinLock または KeAcquireInStackQueuedSpinLock を呼び出すルーチンは、エグゼクティブ スピン ロックを解除し、IRQL = DISPATCH_LEVEL で実行しなくなるまで、ハードウェア例外を発生させることも、ソフトウェア例外を発生させることもできません。

ページング可能なデータとサポート ルーチン

スピン ロックを保持している間、ドライバーはページング可能なデータにアクセスするルーチンを呼び出すことはできません。 ドライバーは、DISPATCH_LEVEL よりも厳密に低い IRQL で実行中に呼び出しが発生した場合、かつその場合に限って、ページング可能なデータにアクセスする特定のサポート ルーチンを呼び出すことができることに注意してください。 この IRQL 制限では、スピン ロックを保持しながらこれらのサポート ルーチンを呼び出すことはできません。 特定のサポート ルーチンの IRQL 要件については、そのルーチンのリファレンス ページを参照してください。

再帰

スピン ロックを再帰的に取得しようとすると、確実にデッドロックが発生します。再帰ルーチンの保持インスタンス化では、2 つ目のインスタンス化スピン中にスピン ロックを解除できず、同じスピン ロックを取得しようとします。

次のガイドラインでは、再帰ルーチンでスピン ロックを使用する方法について説明します。

  • 再帰ルーチンは、スピン ロックを保持しているときにそれ自体を呼び出したり、その後の呼び出しで同じスピン ロックの取得を試行することはできません。

  • 再帰ルーチンはスピン ロックを保持しますが、再帰によってデッドロックが発生したり、呼び出し元がスピン ロックを 25 マイクロ秒を超えて保持したりする可能性がある場合は、別のドライバー ルーチンが再帰ルーチンを呼び出すことはできません。

再帰ドライバー ルーチンの詳細については、「カーネル スタックの使用」を参照してください。

入れ子になったスピン ロックの取得

2 つ目のスピン ロックを取得しようとするときに別のスピン ロックを保持していると、デッドロックやドライバーのパフォーマンス低下が発生する可能性もあります。

次のガイドラインでは、ドライバーがスピン ロックを保持する方法について説明します。

  • ドライバーは、デッドロックが起きない場合を除き、スピン ロックを使用するサポート ルーチンを呼び出すことはできません。

  • デッドロックが起きない場合でも、代替コーディング手法で同等のドライバー パフォーマンスと機能を提供できない場合を除き、ドライバーはスピン ロックを使用するサポート ルーチンを呼び出さないでください。

  • ドライバーがスピン ロックを取得するために入れ子になった呼び出しを行う場合は、取得するたびに常に同じ順序でスピン ロックを取得する必要があります。 この順序を守ると、デッドロックを回避できます。

一般に、共有データとリソースの重複するサブセットまたは個別のセットを保護するために、入れ子になったスピン ロックの使用は避けてください。 ドライバーが 2 つのエグゼクティブ スピン ロックを使用して個別のリソース (さまざまなドライバー ルーチンによって個別にまとめて設定される可能性があるタイマー オブジェクトのペアなど) を保護する場合に起こりそうな事象を検討します。 スピン ロックを 1 つずつ保持している 2 つのルーチンのいずれかが、もう一方のスピン ロックを取得しようとすれば、ドライバーが SMP マシンで断続的にデッドロックを起こします。

入れ子になったスピン ロックの取得の詳細については、「ロック、デッドロック、同期」を参照してください。