関連付けられているデバイス オブジェクトのタイマーが有効になっている間、 IoTimer ルーチンは約 1 秒に 1 回呼び出されます。 ただし、各 IoTimer ルーチンが呼び出される間隔はシステム クロックの解像度によって異なるため、 IoTimer ルーチンが 1 秒の境界で正確に呼び出されるとは想定しないでください。
手記IoTimer ルーチンは、すべての DPC ルーチンと同様に、IRQL = DISPATCH_LEVELで呼び出されます。 DPC ルーチンが実行されている間、すべてのスレッドが同じプロセッサで実行されないようにします。 ドライバー開発者は、できるだけ短時間実行するように IoTimer ルーチンを慎重に設計する必要があります。
IoTimer ルーチンの最も一般的な用途は、IRP のデバイス I/O 操作をタイムアウトすることです。 デバイス ドライバー内で実行中のタイマーとして IoTimer ルーチンを使用する場合は、次のシナリオを検討してください。
デバイスを起動すると、ドライバーはデバイス拡張機能のタイマー カウンターを -1 に初期化し、現在のデバイス I/O 操作がないことを示し、STATUS_SUCCESSを返す直前に IoStartTimer を 呼び出します。
IoTimer ルーチンが呼び出されるたびに、タイマー カウンターが -1 であるかどうかを確認し、存在する場合は制御を返します。
ドライバーの StartIo ルーチンは、デバイス拡張機能のタイマー カウンターを上限に初期化します。 さらに、IoTimer ルーチンが実行された場合は 1 秒が追加されます。 次に 、KeSynchronizeExecution を使用して SynchCritSection_1 ルーチンを呼び出します。このルーチンは、現在の IRP によって要求された操作の物理デバイスをプログラムします。
ドライバーの ISR は、ドライバーの DpcForIsr ルーチンまたは CustomDpc ルーチンをキューする前に、タイマー カウンターを -1 にリセットします。
IoTimer ルーチンが呼び出されるたびに、タイマー カウンターが ISR によって -1 にリセットされたかどうかを確認し、その場合は制御を返します。 そうでない場合、 IoTimer ルーチンは KeSynchronizeExecution を使用して SynchCritSection_2 ルーチンを呼び出します。このルーチンは、ドライバーによって決定された秒数だけタイマー カウンターを調整します。
SynchCritSection_2 ルーチンは、現在の要求がまだタイムアウトしていない限り、IoTimer ルーチンに TRUE を返します。タイマー カウンターが 0 になると、SynchCritSection_2 ルーチンは、ドライバーによって決定されたリセット タイムアウト値にタイマー カウンターをリセットし、そのコンテキスト領域でそれ自体 (および DpcForIsr) に対してリセットが必要なフラグを設定し、デバイスのリセットを試み、TRUE を返します。
SynchCritSection_2 ルーチンは、リセット操作が FALSE を返すときにデバイスでもタイムアウトになった場合に、再度呼び出されます。 リセットが成功した場合、 DpcForIsr ルーチンは、デバイスが reset-expected フラグからリセットされたことを判断し、要求を再試行し、手順 2 で説明されているように StartIo ルーチンのアクションを繰り返します。
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 ルーチンは FALSE を IoTimer ルーチンに返します。
その結果、上記の IoTimer ルーチンとそのヘルパー SynchCritSection_2 ルーチンの両方が、通常の状況で実行するのに非常に少ない時間がかかります。 この方法で IoTimer ルーチンを使用すると、デバイス ドライバーは、必要に応じて、各有効なデバイス I/O 要求を再試行できることを確認し、修正不可能なハードウェア障害によって IRP が満たされない場合にのみ 、CustomDpc ルーチンが IRP を失敗させます。 さらに、ドライバーは、実行時間に非常に少ないコストでこの機能を提供します。
上記のシナリオのシンプルさは、一度に 1 つの操作のみを実行するデバイスと、通常は I/O 操作と重複しないドライバーによって異なります。 重複したデバイス I/O 操作を実行するドライバー、または IoTimer ルーチンを使用して複数の下位ドライバーチェーンに送信されたドライバー割り当て IRP のセットをタイムアウトする上位レベルのドライバーには、管理するより複雑なタイムアウト シナリオがあります。