本節討論實作取消常式以及處理可取消的 IRP 的指導方針。 如需處理可取消 IRP 的詳細資訊,請參閱 Cancel-Safe IRP 佇列的控制流程。
所有取消常式的一般準則
I/O 管理員在任何時候呼叫驅動程式的 Cancel 常式時,會持有取消旋轉鎖定。 因此,每個 取消 常式都必須:
在傳回控制權之前呼叫 IoReleaseCancelSpinLock 。
不要呼叫 IoAcquireCancelSpinLock,除非它已先呼叫 IoReleaseCancelSpinLock。
針對 IoAcquireCancelSpinLock 進行的每個呼叫,都會對 IoReleaseCancelSpinLock 進行互惠呼叫。
每次 Cancel 常式呼叫 IoReleaseCancelSpinLock 時,它都必須傳遞最近呼叫 IoAcquireCancelSpinLock 所傳回的 IRQL。 釋放由 I/O 管理員取得的自旋鎖時,當呼叫 Cancel 常式後保持此狀態,Cancel 常式必須傳遞 Irp->CancelIrql。
驅動程式在持有旋轉鎖時不得呼叫外部常式,例如 IoCompleteRequest,因為可能會導致死結。
使用 I/O 管理程式所定義的佇列
除非驅動程式管理自己的 IRP 內部佇列,否則其 Cancel 常式會使用傳入 IRP 呼叫,該 IRP 可能是下列其中一項:
輸入目標裝置物件中的 CurrentIrp
與目標裝置物件相關聯的裝置佇列中的項目
除非驅動程式管理自己的 IRP 內部佇列,否則其 Cancel 常式應該使用輸入 IRP 呼叫 KeRemoveEntryDeviceQueue ,以測試它是否是與目標裝置物件相關聯的裝置佇列中的專案。 驅動程式的 Cancel 常式 無法 呼叫 KeRemoveDeviceQueue 或 KeRemoveByKeyDeviceQueue ,因為它無法假設指定的 IRP 位於裝置佇列中的任何特定位置。
輸入 IRP 的目前狀態
如果為驅動程式已啟動 I/O 處理的 IRP 呼叫 Cancel 常式,而要求很快就會完成,則 Cancel 常式應該釋放系統取消自旋鎖,並將控制權返回。
如果輸入 IRP 的目前狀態為 [擱置中],則 Cancel 常式必須執行下列動作:
設定輸入 IRP 的 I/O 狀態區塊,狀態為 STATUS_CANCELLED , 資訊為零。
釋放所持有的任何自旋鎖,包括系統取消自旋鎖。
使用指定的 IRP 呼叫 IoCompleteRequest 。
保持 IRP 在可取消狀態
任何處於可取消狀態的 IRP 驅動程式例程都必須呼叫 IoMarkIrpPending ,而且必須呼叫 IoSetCancelRoutine 來設定 IRP 中 Cancel 例程的進入點。 只有這樣,驅動程式例程才能呼叫其他支援例程,例如 IoStartPacket、IoAllocateController 或 ExInterlockedInsertList 例程。
後續處理可取消 IRP 的任何驅動程式例程,都必須檢查 IRP 是否已在開始作業之前取消,以滿足要求。 例程必須呼叫 IoSetCancelRoutine ,將其 取消 例程的進入點重設為IRP中的 NULL 。 只有這樣,該例程才能開始其輸入 IRP 的 I/O 處理。
如果 IRP 中的 取消 例程也需要將 IRP 傳遞給其他驅動程式的例程進行進一步處理,且這些 IRP 可能會處於可取消狀態,那麼可能必須重設該 取消 例程的進入點。
任何處於可取消狀態的 IRP 較高層級驅動程式,都必須將其 [取消 ] 進入點重設為 NULL ,才能使用 IoCallDriver 將 IRP 傳遞給下一個較低的驅動程式。
取消 IRP
任何較高層級的驅動程式都可以使用已配置並傳遞的 IRP 呼叫 IoCancelIrp ,以供較低層級驅動程式進一步處理。 不過,這類驅動程式無法假設指定的 IRP 將會由較低驅動程式以「STATUS_CANCELLED」完成。
同步
驅動程式可以(或必須視其設計而定)在其裝置擴充功能中維護其他狀態資訊,以追蹤 IRP 的可取消狀態。 如果此狀態是由在 IRQL <= DISPATCH_LEVEL 執行的驅動程式例程共用,則共用的資料應該受到驅動程式配置和初始化的旋轉鎖保護。
驅動程式應該仔細管理其獲取和釋放系統取消自旋鎖以及自身的自旋鎖。 它應該在最短的時間內持有系統取消自旋鎖。 存取可取消的 IRP 之前,這類驅動程式應該一律檢查 IoSetCancelRoutine 的傳回值,以判斷 Cancel 例程是否已執行(或即將執行):如果是,它應該讓 Cancel 例程完成 IRP。
如果裝置驅動程式維護與 ISR 共用的、可被各種驅動程式例程取消的 IRP 狀態資訊,這些例程必須對與 ISR 共享的狀態存取進行同步處理。 只有驅動程式提供的 SynchCritSection 例程可以存取以多重處理器安全方式與 ISR 共用的狀態資訊。
如需詳細資訊,請參閱 同步處理技術。