キャンセル ルーチンの実装
I/O マネージャーは、キャンセルする入力 IRP と、I/O 要求のターゲット デバイスを表す DeviceObject ポインターを使用して、ドライバーによって提供されたキャンセル ルーチンを呼び出します。
IRP は、現在の Win32 アプリケーションがユーザーによって閉じられているのと同じように、ドライバーの DispatchReadWrite ルーチンをキューに入れることができます。 IRP は、基になるデバイスの性質に応じて、上位レベルのドライバーが明示的にキャンセルした場合もあります。
キャンセル ルーチンが呼び出されたとき、入力 IRP は、既にターゲット デバイス オブジェクトの CurrentIrp になっているか、ドライバーが StartIo ルーチンを持っている場合はターゲット デバイス オブジェクトに関連付けられているデバイス キューに入っている可能性があります。 ドライバーに StartIo ルーチンがない場合、IRP は、そのキャンセル ルーチンが呼び出されたときに IRP のドライバー管理の内部キューに存在する可能性があります。 いずれの場合も、I/O マネージャーは、受信 IRP のキャンセル ルーチンを呼び出す前に、I/O マネージャーは、この IRP のキャンセル メンバーを TRUE に設定し、IRP の CancelRoutine メンバーを NULL に設定します。
関連付けられた IRP を持つマスター IRP のキャンセル ルーチンは、IoCancelIrp を呼び出して関連付けられている IRP をキャンセルします。
すべてのキャンセル ルーチンは、以下のガイドラインに従う必要があります。
IoReleaseCancelSpinLock を呼び出して、システムのスピン ロックのキャンセルを解放します。
I/O ステータス ブロックの Status メンバーを STATUS_CANCELLED に設定し、その Information メンバーを 0 に設定します。
IoCompleteRequest を呼び出すことで、指定した IRP を完了します。
キャンセル ルーチンは常にシステムキャンセル スピン ロックを保持して呼び出されるため、まず IoReleaseCancelSpinLock を呼び出さない限り、このルーチンが IoAcquireCancelSpinLock を呼び出してはなりません。
キャンセル ルーチンは、制御を返すときに、システムのキャンセル スピン ロックを保持することはできません。 つまり、すべてのキャンセル ルーチンは、制御を返す前に、少なくとも 1 回 IoReleaseCancelSpinLock を呼び出す必要があります。
IoAcquireCancelSpinLock を呼び出した場合、キャンセル ルーチンは、可能な限り迅速に IoReleaseCancelSpinLock への逆呼び出しを行う必要があります。
スピン ロックを保持しながら、IRP で IoCompleteRequest を呼び出してはなりません。 スピン ロックを保持しているときに IRP を完了しようとすると、デッドロックが発生する可能性があります。