啟用相關聯裝置物件的定時器時, IoTimer 例程大約每秒呼叫一次。 不過,由於呼叫每個 IoTimer 例程的間隔取決於系統時鐘的解析度,因此請勿假設 IoTimer 例程會在一秒的界限上精確呼叫。
注意IoTimer 例程,就像所有 DPC 例程一樣,會在 IRQL = DISPATCH_LEVEL 時呼叫。 當 DPC 例程執行時,所有線程都無法在同一個處理器上執行。 驅動程式開發人員應該仔細設計其 IoTimer 例程,盡可能短暫地執行。
IoTimer 例程最常見的用途可能是逾時 IRP 的裝置 I/O 作業。 請考慮使用 IoTimer 例程作為裝置驅動器內執行定時器的下列案例:
啟動裝置時,驅動程式會將裝置擴充功能中的定時器計數器初始化為 -1,指出沒有目前的裝置 I/O 作業,並在它傳回STATUS_SUCCESS之前呼叫 IoStartTimer 。
每次呼叫 IoTimer 例程時,它會檢查定時器計數器是否為 -1,如果是,則會傳回控件。
驅動程式的 StartIo 例程會將裝置延伸模組中的定時器計數器初始化為上限,並在剛執行 IoTimer 例程時再增加一秒。 然後,它會使用 KeSynchronizeExecution 來呼叫 SynchCritSection_1 例程,以針對目前 IRP 所要求的作業來程式設計實體裝置。
每次呼叫 IoTimer 例程時,它會檢查ISR是否已將定時器計數器重設為 -1,如果是,則會傳回控件。 如果沒有, IoTimer 例程會使用 KeSynchronizeExecution 來呼叫 SynchCritSection_2 例程,這會將定時器計數器調整為一些驅動程式決定的秒數。
只要目前的要求尚未逾時,SynchCritSection_2 例程就會將 TRUE 傳回 IoTimer 例程。如果定時器計數器降到零,SynchCritSection_2 例程會將定時器計數器重設為驅動程式決定的重設逾時值,並在其內容區域中為自身及DpcForIsr設定重設預期旗標,嘗試重設裝置,並傳回 TRUE。
如果 SynchCritSection_2 的重設作業在裝置上也超時並傳回 FALSE,則將再次呼叫該例程。 如果重設成功, DpcForIsr 例程會判斷裝置已從重設預期的旗標重設並重試要求,重複 StartIo 例程的動作,如步驟 2 中所述。
如果SynchCritSection_2例程傳回 FALSE,IoTimer 例程會假設實體裝置處於未知狀態,因為嘗試重設它已經失敗。 在這些情況下,IoTimer 例程會排入一個 CustomDpc 例程然後傳回。 此 CustomDpc 例程會記錄裝置 I/O 錯誤、呼叫 IoStartNextPacket、失敗目前的 IRP 並傳回。
如果此裝置驅動程式的ISR將共用定時器計數器重設為 -1,如步驟 3 所述,驅動程式的 DpcForIsr 例程會完成目前 IRP 的中斷驅動 I/O 處理。 重設定時器計數器表示此裝置 I/O 作業未逾時,因此 IoTimer 例程不需要變更定時器計數器。
在大部分情況下,上述 SynchCritSection_2 例程只會遞減定時器計數器。 只有當目前的 I/O 作業逾時時, SynchCritSection_2 例程才會嘗試重設裝置,這表示定時器計數器進入零時。 只有當嘗試重設裝置已經失敗時, SynchCritSection_2 例程才會將 FALSE 傳回 IoTimer 例程。
因此,上述 IoTimer 例程及其協助程式 SynchCritSection_2 例程在正常情況下執行的時間很少。 藉由以這種方式使用 IoTimer 例程,裝置驅動程式可確保可以視需要重試每個有效的裝置 I/O 要求,而且只有在無法更正的硬體故障導致 IRP 無法滿足時, CustomDpc 例程才會失敗 IRP。 此外,驅動程式在執行時間上幾乎不影響地提供這項功能。
上述案例的簡單性取決於一次只執行一個作業的裝置,以及通常不會重疊 I/O 作業的驅動程式。 執行重疊裝置 I/O 作業的驅動程式,或是使用 IoTimer 例程來逾時一組傳送至多個較低驅動程式鏈結的驅動程式配置 IRP,將會有更複雜的逾時案例來管理。