削除ロックの使用

ロック解除 ルーチンは、デバイスで未処理の I/O 操作の数を追跡し、ドライバーのデバイス オブジェクトをデタッチして削除しても安全かどうかを判断する方法を提供します。 システムは、独自の追跡メカニズムを実装する代わりに、ドライバー ライターにこれらのルーチンを提供します。

ドライバーは、次の 2 つの目的でこのメカニズムを使用できます。

  1. ロックが保持されている間 (たとえば、別のドライバー ルーチンがデバイスにアクセスしている間) に、ドライバーの DispatchPnP ルーチンが IRP_MN_REMOVE_DEVICE 要求を完了しないようにします。

  2. ドライバーがデバイス オブジェクトを削除すべきでない理由の数をカウントし、その数が 0 になったときにイベントを設定します。

削除ロックを初期化するには、ドライバーがデバイス拡張機能IO_REMOVE_LOCK 構造体を割り当て、IoInitializeRemoveLock を呼び出す必要があります。 ドライバーは通常、デバイス オブジェクトのデバイス拡張機能の残りの部分を初期化するときに、その AddDevice ルーチンで IoInitializeRemoveLock を呼び出します。

ドライバーは、I/O 操作を開始するたびに IoAcquireRemoveLock を呼び出す必要があります。 ドライバーは、I/O 操作が完了するたびに IoReleaseRemoveLock を呼び出す必要があります。 ドライバーは、ロックを複数回取得できます。 削除ロック ルーチンは、ロックの未処理の取得数を保持します。 IoAcquireRemoveLock を呼び出すたびにカウントがインクリメントされ、IoReleaseRemoveLock によってカウントがデクリメントされます。

ドライバーは、コードへの参照 (タイマー、DPC、コールバックなど) を渡すときにも IoAcquireRemoveLock を呼び出す必要があります。 その後、ドライバーは、イベントが返されたときに IoReleaseRemoveLock を呼び出す必要があります。

IRP_MN_REMOVE_DEVICE のディスパッチ コードでは、ドライバーはもう一度ロックを取得し、IoReleaseRemoveLockAndWait を呼び出す必要があります。 このルーチンは、ロックの未処理の取得がすべて解放されるまで戻りません。 キューに登録された I/O 操作を完了するには、各ドライバーは、IRP_MN_REMOVE_DEVICE 要求を次の下位ドライバーに渡した、およびメモリを解放したり、IoDetachDevice または IoDeleteDevice を呼び出すIoReleaseRemoveLockAndWait を呼び出す必要があります。 特定の削除ロックに対して IoReleaseRemoveLockAndWait が呼び出されると、同じ削除ロックに対する IoAcquireRemoveLock の後続の呼び出しはすべて失敗します。

IoReleaseRemoveLockAndWait が返された後、ドライバーは、デバイスが削除可能な状態であり、I/O 操作を実行できないと見なす必要があります。 そのため、ドライバーは、削除ロックを再初期化する IoInitializeRemoveLock を呼び出す必要があります。 ドライバー検証ツールによるドライバーの検証中に、この規則に違反すると、バグ チェックが発生します。

ドライバーが、デバイス オブジェクトのデバイス拡張機能に IO_REMOVE_LOCK 構造体を格納するため、IRP_MN_REMOVE_DEVICE 要求の処理中にデバイス拡張機能を削除すると、削除ロックが削除されます。