前言 :
系統定義的 StartIO 常式只能使用一個佇列, 這個佇列會將所有的 IRP 進行處理與分配. 這樣讀, 寫操作就會混在一起進行連續處理. 然而在某些情況下, 需要將讀, 寫分別進行序列化處理. 這時候就需要自訂 StartIO 常式.
多個序列化佇列 :
你可能會發現 StartIO 雖然可以很方便地將 IRP 序列化, 但是存在一個問題, 這就是讀寫操作都被一起序列化. 有時候需要將讀, 寫分開序列化, 便需要兩個佇列. 一個佇列序列 IRP_MJ_READ 類型 IRP, 另外一個佇列負責序列化 IRP_MJ_WRITE 類型的 IRP.
但是很遺憾是 DDK 提供的 StartIO 常式內部只有一個佇列, 無法實現上述的需求. 但是 DDK 提供了一種更靈活的方式 - 自訂 StartIO. 自訂 StartIO 類似於前面介紹的 StartIO 常式, 不同的是程式設計師要自己維護 IRP 佇列. 設計師可以靈活維護多個佇列, 分別應用於不同的類型的 IRP. DDK 提供 KDEVICE_QUEUE 資料結構儲存佇列 :
佇列中每個元素用 KDEVICE_QUEUE_ENTRY 資料結構表示 :
在 StartIO 的內部也用到這種佇列. 但當使用 StartIO 時, 程式員不用關心佇列的 "入隊" 和 "出隊" 操作, 這些都由作業系統負責. 而當使用自訂 StartIO 時, 程式員需要自己負責 "入隊" 和 "出隊" 操作. 在使用佇列前, 應該初始化佇列, 用 KeInitializeDeviceQueue 函式初始化佇列. 佇列應該儲存在裝制擴充中, 在初始化裝置的時候一起初始化該佇列. 插入佇列的內核函式是 KeInsertDeviceQueue, 其宣告如下 :
參數說明 :
從佇列中刪除元素使用 KeRemoveDeviceQueue 函式, 其宣告如下 :
參數說明 :
示例 :
這裡將演式如何編寫自訂 StartIO 常式.
首先應該在裝置擴充中加入 KDEVICE_QUEUE 資料結構儲存佇列, 並且在 DriverEntry 中初始化該佇列. 如果程式設計師需要對讀和寫操作分別序列化, 可以在裝置擴充新建兩個佇列, 分別對應讀和寫. 這裡只示範一個佇列的做法, 讀者可以試著為自己的驅動加入更多的佇列.
接著是編寫派遣常式, 在派遣函式中首先用 IoMarkIrpPending 函式將該 IRP 設為 "Pending", 然後準備將 IRP 存入佇列. 在進入佇列前要先將當前 IRQL 提升至 DISPATCH_LEVEL 層級. 插入佇列使用 KeInsertDeviceQueue 函式, 該函式的返回值指示是否需要立即執行. 當該函式返回 FALSE 的時候, 表明 IRP 沒有插入到佇列, 而是需要被立刻執行. 這時候需要呼叫自訂的 StartIO 常式 :
接下來編寫自訂 StartIO 常式. 自訂 StartIO 的任務是首先處理傳進來的 IRP, 然後在枚舉佇列中的 IRP, 接著依次出佇列並對其進行處理 :
底下為執行結果 :
系統定義的 StartIO 常式只能使用一個佇列, 這個佇列會將所有的 IRP 進行處理與分配. 這樣讀, 寫操作就會混在一起進行連續處理. 然而在某些情況下, 需要將讀, 寫分別進行序列化處理. 這時候就需要自訂 StartIO 常式.
多個序列化佇列 :
你可能會發現 StartIO 雖然可以很方便地將 IRP 序列化, 但是存在一個問題, 這就是讀寫操作都被一起序列化. 有時候需要將讀, 寫分開序列化, 便需要兩個佇列. 一個佇列序列 IRP_MJ_READ 類型 IRP, 另外一個佇列負責序列化 IRP_MJ_WRITE 類型的 IRP.
但是很遺憾是 DDK 提供的 StartIO 常式內部只有一個佇列, 無法實現上述的需求. 但是 DDK 提供了一種更靈活的方式 - 自訂 StartIO. 自訂 StartIO 類似於前面介紹的 StartIO 常式, 不同的是程式設計師要自己維護 IRP 佇列. 設計師可以靈活維護多個佇列, 分別應用於不同的類型的 IRP. DDK 提供 KDEVICE_QUEUE 資料結構儲存佇列 :
佇列中每個元素用 KDEVICE_QUEUE_ENTRY 資料結構表示 :
在 StartIO 的內部也用到這種佇列. 但當使用 StartIO 時, 程式員不用關心佇列的 "入隊" 和 "出隊" 操作, 這些都由作業系統負責. 而當使用自訂 StartIO 時, 程式員需要自己負責 "入隊" 和 "出隊" 操作. 在使用佇列前, 應該初始化佇列, 用 KeInitializeDeviceQueue 函式初始化佇列. 佇列應該儲存在裝制擴充中, 在初始化裝置的時候一起初始化該佇列. 插入佇列的內核函式是 KeInsertDeviceQueue, 其宣告如下 :
參數說明 :
從佇列中刪除元素使用 KeRemoveDeviceQueue 函式, 其宣告如下 :
參數說明 :
示例 :
這裡將演式如何編寫自訂 StartIO 常式.
首先應該在裝置擴充中加入 KDEVICE_QUEUE 資料結構儲存佇列, 並且在 DriverEntry 中初始化該佇列. 如果程式設計師需要對讀和寫操作分別序列化, 可以在裝置擴充新建兩個佇列, 分別對應讀和寫. 這裡只示範一個佇列的做法, 讀者可以試著為自己的驅動加入更多的佇列.
接著是編寫派遣常式, 在派遣函式中首先用 IoMarkIrpPending 函式將該 IRP 設為 "Pending", 然後準備將 IRP 存入佇列. 在進入佇列前要先將當前 IRQL 提升至 DISPATCH_LEVEL 層級. 插入佇列使用 KeInsertDeviceQueue 函式, 該函式的返回值指示是否需要立即執行. 當該函式返回 FALSE 的時候, 表明 IRP 沒有插入到佇列, 而是需要被立刻執行. 這時候需要呼叫自訂的 StartIO 常式 :
接下來編寫自訂 StartIO 常式. 自訂 StartIO 的任務是首先處理傳進來的 IRP, 然後在枚舉佇列中的 IRP, 接著依次出佇列並對其進行處理 :
底下為執行結果 :
This message was edited 5 times. Last update was at 17/01/2011 15:59:58
沒有留言:
張貼留言