共用方式為


使用自動同步處理

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

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

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

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

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

物件類型 同步處理回呼函式

Queue 物件

要求處理程式EvtIoQueueStateEvtIoResumeEvtIoStop

檔案物件

所有 回呼函式

請求物件

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

若要使用架構為所有裝置提供裝置層級同步處理,請將SynchronizationScope設定為驅動程式驅動程式物件的WDF_OBJECT_ATTRIBUTES結構中的 WdfSynchronizationScopeDevice。 針對每個裝置物件使用預設 WdfSynchronizationScopeInheritFromParent 值。

若要為個別裝置提供裝置層級同步處理,請使用驅動程式對象的預設 WdfSynchronizationScopeNone 值。 在個別裝置物件的WDF_OBJECT_ATTRIBUTES結構中,將 SynchronizationScope 設定為 WdfSynchronizationScopeDevice

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

  • 針對 Framework 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

調度層級

WdfSynchronizationScopeQueue

WdfExecutionLevelPassive

被動層級

WdfSynchronizationScopeQueue

WdfExecutionLevelDispatch

調度級別 (DISPATCH_LEVEL)

WdfSynchronizationScopeNone

WdfExecutionLevelPassive

被動層級

WdfSynchronizationScopeNone

WdfExecutionLevelDispatch

<= DISPATCH_LEVEL

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

您應該在以下情況下指定 WdfExecutionLevelPassive

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

  • 驅動程式的回呼函式必須存取可分頁的程式代碼或數據。 例如,檔案物件回呼函式通常會存取可分頁的數據。

驅動程式可以設定WdfExecutionLevelDispatch,而不是設定WdfExecutionLevelPassive,並提供回呼函式,以便在必須在 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。