取消 IRP 時要考慮的點

本節討論實作 Cancel 例程和處理可取消 IRP 的指導方針。 如需處理可取消 IRP 的詳細資訊,請參閱 Cancel-Safe IRP 佇列的控制流程

所有取消例程的一般指導方針

每當呼叫驅動程式的 Cancel 例程時,I/O 管理員都會保留取消微調鎖定。 因此,每個 Cancel 例程都必須:

  • 在傳回控件之前呼叫 IoReleaseCancelSpinLock

  • 除非先呼叫 IoReleaseCancelSpinLock,否則請勿呼叫 IoAcquireCancelSpinLock

  • 針對對 IoAcquireCancelSpinLock 進行的每個呼叫,對 IoReleaseCancelSpinLock 進行相互呼叫。

每次 Cancel 例程呼叫 IoReleaseCancelSpinLock 時,它都必須傳遞最近呼叫 IoAcquireCancelSpinLock 所傳回的 IRQL。 釋放 I/O 管理員取得的微調鎖定 (,並在呼叫 Cancel 例程時保留) ,Cancel 例程必須通過 Irp-CancelIrql>

驅動程式不能呼叫外部例程 (,例如 IoCompleteRequest) ,同時按住微調鎖定,因為死結可能會造成。

使用 I/O 管理員定義的佇列

除非驅動程式管理自己的 IRP 內部佇列,否則其 Cancel 例程會使用可能是下列其中一項的傳入 IRP 呼叫:

  • 輸入目標裝置物件中的 CurrentIrp

  • 與目標裝置對象相關聯的裝置佇列中的專案

除非驅動程式管理自己的 IRP 內部佇列,否則其 Cancel 例程應該使用輸入 IRP 呼叫 KeRemoveEntryDeviceQueue ,以測試它是否為與目標裝置對象相關聯的裝置佇列中的專案。 驅動程式的 Cancel 例程 無法 呼叫 KeRemoveDeviceQueueKeRemoveByKeyDeviceQueue ,因為它無法假設指定的 IRP 位於裝置佇列中的任何特定位置。

輸入 IRP 的目前狀態

如果使用已啟動 I/O 處理的 IRP 呼叫 Cancel 例程,且要求即將完成, 則 Cancel 例程應該釋放系統取消微調鎖定並傳回控件。

如果輸入 IRP 的目前狀態為 Pending, 則 Cancel 例程必須執行下列動作:

  1. 針對 [狀態] 設定輸入 IRP 的 I/O 狀態區塊,並針對 [資訊] 設定STATUS_CANCELLED。

  2. 釋放它所持有的任何微調鎖定,包括系統取消微調鎖定。

  3. 使用指定的 IRP 呼叫 IoCompleteRequest

保留可取消狀態的 IRP

任何處於可取消狀態的 IRP 驅動程式例程都必須呼叫 IoMarkIrpPending ,而且必須呼叫 IoSetCancelRoutine 來設定 IRP 中 Cancel 例程的進入點。 只有這樣,驅動程式例程才能呼叫其他支援例程,例如 IoStartPacketIoAllocateControllerExInterlockedInsert。列出 例程。

後續處理可取消 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 共用的狀態資訊。

如需詳細資訊,請參閱 同步處理技術