在驅動程式中, 一般有兩種方式使用計時器, 一種方法是使用 I/O 計時器常式, 另一種方法是使用 DPC 常式. 這裡將介紹如何使用 I/O 計時器常式.
I/O 計時器 :
I/O 計時器是 DDK 提供的一種計時器. 使用這種計時器, 每間隔 1s 鐘系統會呼叫一次 I/O 計時器常式. 設計師可以對這種計時器稍加改進, 在計時器常式中記錄某一個計數, 初始值設置為 N. 每次進入計時器的時候計數減一, 當計數歸零時, 執行某項操作, 並將計數還原為 N. 這樣間隔 1s 的計時器就變化為間隔 N s的計時器.
I/O 計時器可以間隔 Ns 做定時, 但如果要實作對 ms 層級間隔甚至更小單位, 則需要用到另一種計時機制 (下一節介紹的 DPC 計時器). 在使用 I/O 計時器前需要先進行初始化, 初始化 I/O 計時器使用內核函式 IoInitializeTimer, 其宣告如下 :
在初始化 I/O 計時器後, 可以開啟與停止 I/O 計時器. 開啟計時器後, 每隔一秒, 系統呼叫一次計時器常式. 在停止計時器後, 系統就不會進入計時器常式. 開啟計時器的內核函式是IoStartTimer, 停止 I/O 計時器的內核函式是 IoStopTimer.
需要指出的是, I/O 計時器常式執行在 DISPATCH_LEVEL 層級, 因此在這個常式中不能使用分頁記憶體, 否則會引起頁故障而導致系統崩潰. 另外 I/O 計時器是執行在任意執行緒的, 不一定是 IRP 發起的執行緒中, 因此不能直接使用應用程式的記憶體.
示例程式碼 :
下面的例子演示了如何在驅動程式中使用 I/O 計時器. 這個例子每隔一秒進入 I/O 計時器常式, 每隔 3 秒輸出一行除錯資訊. 首先在 DriverEntry 中對 I/O 計時器進行初始化 :
- ...
- IoInitializeTimer(pDeviceObj, OnTimer, NULL);
- ...
- typedef struct _DEVICE_EXTENSION {
- ...
- LONG lTimerCount; // 計數變數
- ...
- } DEVICE_EXTENSION, *PDEVICE_EXTENSION;
下面編寫計時常式, 這個常式是執行在 DISPATCH_LEVEL 的 IRQL 層級. 首先注意這個常式中不能使用分頁計憶體, 另外在函式首部要使用 #pragma LOCKEDCODE. 為了證明該執行緒可以執行在任意執行緒 Context, 在這個常式的最後, 我們得到當前執行緒的名稱, 並用 log 資訊將其輸出 :
接著在 User mode 程序發起 IOCTL 呼叫 :
下圖為執行後 log 輸出結果, 每個 1s 進入一次 I/O 計時器常式, 另外實做了每隔 3s 輸出一行除錯資訊. I/O 計時器常式還列出當前的處理程序名, 可以發現呼叫函式 OnTimer 的並不是發起 IOCTL 請求的處理程序.
Idle 處理程序和系統處理程序一樣, 都是一種特殊處理程序, 他沒有對應的 exe 檔與之對應, 在 Windows 啟動後這兩個程序就存在於系統中了.
沒有留言:
張貼留言