使用 IoTimer 常式
啟用相關聯裝置物件的計時器時, 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 所要求的作業來程式設計實體裝置。
驅動程式的 ISR 會將計時器計數器重設為 -1,再將驅動程式的 DpcForIsr 常式或 CustomDpc 常式排入佇列。
每次呼叫 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 要求,而且 CustomDpc 常式只有在無法更正的硬體故障防止滿足 IRP 時,才會失敗 IRP。 此外,驅動程式在執行時間提供這項功能的成本很少。
上述案例的簡單性取決於一次只執行一項作業的裝置,以及通常不會重迭 I/O 作業的驅動程式。 執行重迭裝置 I/O 作業的驅動程式,或使用 IoTimer 常式來逾時一組傳送給多個較低驅動程式鏈結的驅動程式配置 IRP,將會有更複雜的逾時案例來管理。