使用自動同步處理

架構驅動程式中的所有程式碼幾乎都位於事件回呼函式中。 架構會自動同步處理驅動程式的大部分回呼函式,如下所示:

架構會使用一組內部同步處理鎖定來實作此自動同步處理。 架構可確保兩個以上的執行緒無法同時呼叫相同的回呼函式,因為每個執行緒必須等到它才能取得同步處理鎖定,再呼叫回呼函式。 (選擇性地,驅動程式也可以在必要時取得這些同步處理鎖定。如需詳細資訊,請參閱 使用 Framework Locks.)

您的驅動程式應該將物件特定資料儲存在 物件內容空間中。 如果您的驅動程式只使用架構定義的介面,則只有接收物件控制碼的回呼函式可以存取此資料。 如果架構正在同步處理對驅動程式回呼函式的呼叫,一次只會呼叫一個回呼函式,而且物件的內容空間一次只能存取一個回呼函式。

除非您的驅動程式實作 被動層級中斷處理,否則服務中斷和存取中斷資料的程式碼必須在裝置的 IRQL (DIRQL) 執行,而且需要額外的同步處理。 如需詳細資訊,請參閱 同步處理中斷程式碼

如果您的驅動程式啟用自動同步處理處理 I/O 要求的回呼函式,架構會同步處理這些回呼函式,以便一次執行一個回呼函式。 下表列出架構同步處理的回呼函式。

物件型別 同步處理的回呼函式

Queue 物件

要求處理常式EvtIoQueueStateEvtIoResumeEvtIoStop

File 物件

所有 回呼函式

要求物件

EvtRequestCancel

或者,架構也可以將這些回呼函式與驅動程式提供給裝置的任何中斷、DPC、工作專案和計時器物件回呼函式同步處理, (排除中斷物件的 EvtInterruptIsr 回呼函式) 。 若要啟用這個額外的同步處理,驅動程式必須將這些物件的組態結構的 AutomaticSerialization 成員設定為 TRUE

總而言之,架構的自動同步處理功能提供下列功能:

  • 架構一律會同步處理每個裝置的 PnP 和電源管理回呼函式。

  • 或者,架構可以同步處理 I/O 佇列的要求處理常式,以及一些額外的回呼函式 (請參閱上表) 。

  • 驅動程式可以要求架構同步處理中斷、DPC、工作專案和計時器物件的回呼函式。

  • 驅動程式必須使用 同步處理中斷程式碼中所述的技術,來同步處理服務中斷和存取中斷資料的程式碼。

  • 架構不會同步驅動程式的其他回呼函式,例如驅動程式的 CompletionRoutine 回呼函式,或 I/O 目標物件所定義的回呼函式。 相反地,架構會提供驅動程式可用來同步處理這些回呼函式的額外 鎖定

選擇同步處理範圍

您可以選擇讓架構同步處理所有與裝置 I/O 佇列相關聯的回呼函式。 或者,您可以選擇讓架構個別同步處理每個裝置 I/O 佇列的回呼函式。 驅動程式可用的同步處理選項如下所示:

  • 裝置層級同步處理

    架構會針對所有裝置的 I/O 佇列同步處理上表所包含的回呼函式,以便一次執行一個。 架構會先取得裝置的同步處理鎖定,再呼叫回呼函式,以達到此同步處理。

  • 佇列層級同步處理

    架構會針對每個個別 I/O 佇列同步處理上表所包含的回呼函式,以便一次執行一個。 架構會先取得佇列的同步鎖定,再呼叫回呼函式,以達到此同步處理。

  • 無同步

    架構不會同步處理上表包含的回呼函式執行,也不會在呼叫回呼函式之前取得同步處理鎖定。 如果需要同步處理,驅動程式必須提供它。

若要指定架構是否要為驅動程式提供裝置層級同步處理、佇列層級同步處理,或沒有同步處理驅動程式,您可以為驅動程式物件、裝置物件或佇列物件指定 同步處理範圍 。 物件的WDF_OBJECT_ATTRIBUTES結構的SynchronizationScope成員會識別物件的同步處理範圍。 驅動程式可以指定的同步處理範圍值如下:

WdfSynchronizationScopeDevice
架構會藉由取得裝置物件的同步處理鎖定來同步處理。

WdfSynchronizationScopeQueue
架構會藉由取得佇列物件的同步處理鎖定來同步處理。

WdfSynchronizationScopeNone
架構不會同步處理,也不會取得同步處理鎖定。

WdfSynchronizationScopeInheritFromParent
架構會從物件的父物件取得物件的 SynchronizationScope 值。

一般而言,我們不建議使用裝置層級同步處理。

如需同步處理範圍值的詳細資訊,請參閱 WDF_SYNCHRONIZATION_SCOPE

驅動程式物件的預設同步處理範圍是 WdfSynchronizationScopeNone。 裝置和佇列物件的預設同步處理範圍是 WdfSynchronizationScopeInheritFromParent

如果您想要架構為所有裝置提供裝置層級同步處理,您可以使用下列步驟:

  1. 在驅動程式驅動程式物件的WDF_OBJECT_ATTRIBUTES結構中,將SynchronizationScope設定為WdfSynchronizationScopeDevice

  2. 針對每個裝置物件使用預設的 WdfSynchronizationScopeInheritFromParent值。

或者,若要提供個別裝置的裝置層級同步處理,您可以使用下列步驟:

  1. 使用驅動程式物件的預設WdfSynchronizationScopeNone值。

  2. SynchronizationScope設定為個別裝置物件WDF_OBJECT_ATTRIBUTES結構中的WdfSynchronizationScopeDevice

如果您想要架構為裝置提供佇列層級同步處理,可以使用下列技術:

  • 針對架構 1.9 版和更新版本,您應該在佇列物件的WDF_OBJECT_ATTRIBUTES結構中設定WdfSynchronizationScopeQueue,以啟用個別佇列的佇列層級同步處理。 這是慣用的技術。

  • 或者,您可以在所有架構版本中使用下列步驟:

    1. 裝置物件的WDF_OBJECT_ATTRIBUTES結構中,將SynchronizationScope設定為WdfSynchronizationScopeQueue
    2. 針對每個裝置的佇列物件使用預設WdfSynchronizationScopeInheritFromParent值。

如果您不想讓架構同步處理處理驅動程式 I/O 要求的回呼函式,請使用驅動程式驅動程式、裝置和佇列物件的預設 SynchronizationScope 值。 在此情況下,架構不會自動同步驅動程式的 I/O 要求相關回呼函式,而且可以在 IRQL < = DISPATCH_LEVEL呼叫回呼函式。

請注意,設定 SynchronizationScope 值只會同步處理上表所包含的回呼函式。 如果您想要架構也同步處理驅動程式的中斷、DPC、工作專案和計時器物件回呼函式,驅動程式必須將這些物件的組態結構的 AutomaticSerialization 成員設定為 TRUE

不過,只有當您想要同步處理的所有回呼函式都在同一 IRQL 上執行時,才可以將 AutomaticSerialization 設定為 TRUE 。 選擇下一個描述的執行 層級可能會導致 IRQL 層級不相容。 在這種情況下,驅動程式必須使用 架構鎖定 ,而不是設定 AutomaticSerialization。 如需中斷、DPC、工作專案和計時器物件之組態結構的詳細資訊,以及這些結構中設定 AutomaticSerialization 的限制詳細資訊,請參閱 WDF_INTERRUPT_CONFIGWDF_DPC_CONFIGWDF_WORKITEM_CONFIGWDF_TIMER_CONFIG

如果您將 AutomaticSerialization 設定為 TRUE,您應該選取佇列層級同步處理。

選擇執行層級

當驅動程式建立某些類型的架構物件時,它可以指定物件的 執行層級 。 執行層級會指定 IRQL,架構會呼叫處理驅動程式 I/O 要求的物件事件回呼函式。

如果驅動程式提供執行層級,則提供的層級會影響佇列和檔案物件的回呼函式。 一般而言,如果驅動程式使用自動同步處理,架構會在 IRQL = DISPATCH_LEVEL呼叫這些回呼函式。 藉由指定執行層級,驅動程式可以強制架構在 IRQL = PASSIVE_LEVEL呼叫這些回呼函式。 當設定呼叫佇列和檔案物件回呼函式的 IRQL 時,架構會使用下列規則:

  • 如果驅動程式使用自動同步處理,除非驅動程式要求架構在 IRQL = PASSIVE_LEVEL呼叫其回呼函式,否則會在 IRQL = DISPATCH_LEVEL呼叫其佇列和檔案物件回呼函式。

  • 如果驅動程式未使用自動同步處理,而且未指定執行層級,則可以在 IRQL < = DISPATCH_LEVEL呼叫驅動程式的佇列和檔案物件回呼函式。

請注意,如果您的驅動程式提供檔案物件回呼函式,您很可能希望架構在 IRQL = PASSIVE_LEVEL呼叫這些回呼函式,因為某些檔案資料,例如檔案名是可分頁的。

若要提供執行層級,您的驅動程式必須指定物件WDF_OBJECT_ATTRIBUTES結構之 ExecutionLevel成員的值。 驅動程式可以指定的執行層級值如下:

WdfExecutionLevelPassive
架構會在 IRQL = PASSIVE_LEVEL呼叫物件的回呼函式。

WdfExecutionLevelDispatch
架構可以在 IRQL < = DISPATCH_LEVEL呼叫物件的回呼函式。 (如果驅動程式使用自動同步處理,架構一律會在 IRQL = DISPATCH_LEVEL.) 呼叫回呼函式

WdfExecutionLevelInheritFromParent
架構會從物件的父系取得物件的 ExecutionLevel 值。

驅動程式物件的預設執行層級是 WdfExecutionLevelDispatch。 所有其他物件的預設執行層級是 WdfExecutionLevelInheritFromParent

如需執行層級值的詳細資訊,請參閱 WDF_EXECUTION_LEVEL

下表顯示 IRQL 層級,架構可以針對佇列物件和檔案物件呼叫驅動程式的回呼函式。

同步處理範圍 執行層級 佇列和檔案回呼函式的 IRQL

WdfSynchronizationScopeDevice

WdfExecutionLevelPassive

PASSIVE_LEVEL

WdfSynchronizationScopeDevice

WdfExecutionLevelDispatch

DISPATCH_LEVEL

WdfSynchronizationScopeQueue

WdfExecutionLevelPassive

PASSIVE_LEVEL

WdfSynchronizationScopeQueue

WdfExecutionLevelDispatch

DISPATCH_LEVEL

WdfSynchronizationScopeNone

WdfExecutionLevelPassive

PASSIVE_LEVEL

WdfSynchronizationScopeNone

WdfExecutionLevelDispatch

<= DISPATCH_LEVEL

您可以將驅動程式、裝置、檔案、佇列、計時器和一般物件的執行層級設定為 WdfExecutionLevelPassiveWdfExecutionLevelDispatch 。 對於其他物件,只允許 WdfExecutionLevelInheritFromParent

如果下列條件,您應該指定 WdfExecutionLevelPassive

  • 驅動程式的回呼函式必須呼叫架構方法或 Windows 驅動程式模型 (WDM) 常式,這些常式只能在 IRQL = PASSIVE_LEVEL呼叫。

  • 驅動程式的回呼函式必須存取可分頁程式碼或資料。 (例如,檔案物件回呼函式通常會存取可分頁的 data.)

驅動程式可以設定WdfExecutionLevelDispatch,並提供回呼函式,以在 IRQL = PASSIVE_LEVEL處理某些作業時,提供可建立工作專案的回呼函式。

在您決定驅動程式是否應該將物件的執行層級設定為 WdfExecutionLevelPassive之前,您應該先判斷呼叫驅動程式堆疊中驅動程式和其他驅動程式的 IRQL。 請考慮下列情況:

  • 如果您的驅動程式位於核心模式驅動程式堆疊頂端,則系統通常會在 IRQL = PASSIVE_LEVEL呼叫驅動程式。 這類驅動程式的用戶端可能是 UMDF 型驅動程式或使用者模式應用程式。 指定 WdfExecutionLevelPassive 不會對驅動程式的效能造成負面影響,因為架構不需要將驅動程式的呼叫排入 IRQL = PASSIVE_LEVEL呼叫的工作專案。

  • 如果您的驅動程式不在堆疊頂端,系統可能不會在 IRQL = PASSIVE_LEVEL呼叫您的驅動程式。 因此,架構必須將驅動程式對工作專案的呼叫排入佇列,稍後會在 IRQL = PASSIVE_LEVEL呼叫。 相較于允許在 IRQL < = DISPATCH_LEVEL呼叫驅動程式的回呼函式,此程式可能會導致驅動程式效能不佳。

對於 DPC 物件,以及不代表被動層級計時器的計時器物件,請注意,如果您已將父裝置的執行層級設定為WdfExecutionLevelPassive,則無法將組態結構的AutomaticSerialization成員設定為TRUE。 這是因為架構會在 IRQL = PASSIVE_LEVEL取得裝置物件的 回呼同步處理鎖定 ,因此鎖定無法用來同步處理必須在 IRQL = DISPATCH_LEVEL的 DPC 或計時器物件回呼函式。 在這種情況下,您的驅動程式應該在任何必須彼此同步處理的裝置、DPC 或計時器物件回呼函式中使用 架構微調鎖定

另請注意,對於確實代表被動層級計時器的計時器物件,只有當父裝置的執行層級設定為WdfExecutionLevelPassive,才能將組態結構的AutomaticSerialization成員設定為 TRUE。