IoTimer ルーチンの使用

関連付けられているデバイス オブジェクトのタイマーが有効になっている間、IoTimer ルーチンは約 1 秒に 1 回呼び出されます。 ただし、各 IoTimer ルーチンが呼び出される間隔はシステム クロックの解像度によって異なるため、IoTimer ルーチンが 1 秒の境界で正確に呼び出されることを前提にしないでください。

注: IoTimer ルーチンは、すべての DPC ルーチンと同様に、IRQL = DISPATCH_LEVEL で呼び出されます。 DPC ルーチンの実行中は、すべてのスレッドは同じプロセッサで実行されません。 ドライバー開発者は、できるだけ短時間で実行されるように IoTimer ルーチンを慎重に設計する必要があります。

IoTimer ルーチンの最も一般的な用途は、IRP のデバイス I/O 操作をタイム アウトにすることです。 デバイス ドライバー内で実行中のタイマーとして IoTimer ルーチンを使用する場合は、次のシナリオを検討してください。

  1. デバイスを起動すると、ドライバーはデバイス拡張機能のタイマー カウンターを -1 に初期化し、現在のデバイス I/O 操作がないことを示し、STATUS_SUCCESS を返す直前に IoStartTimer を呼び出します。

    IoTimer ルーチンが呼び出されるたびに、タイマー カウンターが -1 であるかどうかをチェックし、その場合は制御を返します。

  2. ドライバーの StartIo ルーチンは、デバイス拡張機能のタイマー カウンターを上限まで初期化し、IoTimer ルーチンが実行された場合にはさらに 1 秒追加されます。 次に、KeSynchronizeExecution を使用して SynchCritSection_1 ルーチンを呼び出します。このルーチンは、現在の IRP によって要求された操作の物理デバイスをプログラムします。

  3. ドライバーの ISR は、ドライバーの DpcForIsr ルーチンまたは CustomDpc ルーチンをキューに登録する前に、タイマー カウンターを -1 にリセットします。

  4. IoTimer ルーチンが呼び出されるたびに、タイマー カウンターが ISR によって -1 にリセットされたかどうかがチェックされ、リセットされた場合は制御が返されます。 そうでない場合、IoTimer ルーチンは KeSynchronizeExecution を使用して SynchCritSection_2 ルーチンを呼び出します。このルーチンは、ドライバーによって決定された秒数だけタイマー カウンターを調整します。

  5. SynchCritSection_2 ルーチンは、現在の要求がまだタイム アウトしていない限り、IoTimer ルーチンに TRUE を返します。タイマー カウンターが 0 になると、SynchCritSection_2 ルーチンは、ドライバーによって決定されたリセットタイムアウト値にタイマー カウンターをリセットし、そのコンテキスト領域でそれ自体 (および DpcForIsr) に対してリセットが必要なフラグを設定し、デバイスのリセットを試み、TRUE を返します。

    SYNCHCRITSECTION_2 ルーチンは、FALSE を返すときに、リセット操作もデバイスでタイム アウトになった場合に再度呼び出されます。 リセットが成功した場合、DpcForIsr ルーチンは、デバイスが reset-expected フラグからリセットされたことを判断し、要求を再試行し、手順 2 で説明されているように StartIo ルーチンのアクションを繰り返します。

  6. SynchCritSection_2 ルーチンが FALSE を返した場合、IoTimer ルーチンは、物理デバイスのリセットが既に失敗しているため、物理デバイスが不明な状態であると見なします。 このような状況では、IoTimer ルーチンは CustomDpc ルーチンをキューに入れ、戻ります。 この CustomDpc ルーチンは、デバイス I/O エラーをログに記録し、IoStartNextPacket を呼び出し、現在の IRP に失敗し、戻ります。

手順 3 で説明されているように、このデバイス ドライバーの ISR が共有タイマー カウンターを -1 にリセットした場合、ドライバーの DpcForIsr ルーチンは、現在の IRP の割り込み駆動 I/O 処理を完了します。 リセット タイマー カウンターは、このデバイスの I/O 操作がタイム アウトしていないことを示すので、IoTimer ルーチンはタイマー カウンターを変更する必要はありません。

ほとんどの状況では、上記の SynchCritSection_2 ルーチンはタイマー カウンターをデクリメントするだけです。 SynchCritSection_2 ルーチンは、現在の I/O 操作がタイム アウトした場合にのみデバイスのリセットを試みます。これは、タイマー カウンターが 0 になったときに示されます。 また、デバイスのリセットが既に失敗した場合にのみ、SynchCritSection_2 ルーチンは FALSEIoTimer ルーチンに返します。

その結果、先の IoTimer ルーチンとそのヘルパー SynchCritSection_2 ルーチンの両方が実行する時間は、通常の状況であれば、ほとんどかかりません。 この方法で IoTimer ルーチンを使用すると、デバイス ドライバーは、必要に応じて、各有効なデバイス I/O 要求を再試行できることを確認し、修正不可能なハードウェア障害によって IRP が満たされない場合にのみ、CustomDpc ルーチンが IRP を失敗させます。 さらに、ドライバーは、非常に少ない実行時間でこの機能を提供します。

上記のシナリオの簡潔さは、一度に 1 つの操作のみを実行するデバイスと、通常は I/O 操作が重複しないドライバーに依存します。 重複したデバイス I/O 操作を実行するドライバー、または IoTimer ルーチンを使用して複数の下位ドライバー チェーンに送信されるドライバー割り当て IRP のセットをタイムアウトする上位レベルのドライバーでは、管理するタイム アウト シナリオがより複雑になります。