使用自動同步處理
架構驅動程式中的所有程式碼幾乎都位於事件回呼函式中。 架構會自動同步處理驅動程式的大部分回呼函式,如下所示:
架構一律會同步 處理一般裝置物件、 功能裝置物件 (FDO) 和 實體裝置物件, (PDO) 事件回呼函式彼此同步,因此每個裝置一次只能呼叫其中一個回呼函式 (,但 EvtDeviceQueryRemoval、 EvtDeviceQueryRemove和 EvtDeviceQueryStop) 。 這些回呼函式支援 隨插即用 (PnP) 和電源管理事件,並在 IRQL = PASSIVE_LEVEL呼叫。
或者,架構可以同步處理處理驅動程式 I/O 要求的回呼函式執行,讓這些回呼函式一次執行一個。 具體而言,架構可以同步處理 佇列、 中斷、 延遲程序呼叫 (DPC) 、 計時器、 工作專案和 檔案 物件,以及要求物件的 EvtRequestCancel 回呼函式。 架構會在 IRQL = DISPATCH_LEVEL呼叫大部分的回呼函式,但您可以強制佇列和檔案物件回呼函式在 IRQL = PASSIVE_LEVEL執行。 (工作專案回呼函式一律在 PASSIVE_LEVEL.) 執行
架構會使用一組內部同步處理鎖定來實作此自動同步處理。 架構可確保兩個以上的執行緒無法同時呼叫相同的回呼函式,因為每個執行緒必須等到它才能取得同步處理鎖定,再呼叫回呼函式。 (選擇性地,驅動程式也可以在必要時取得這些同步處理鎖定。如需詳細資訊,請參閱 使用 Framework Locks.)
您的驅動程式應該將物件特定資料儲存在 物件內容空間中。 如果您的驅動程式只使用架構定義的介面,則只有接收物件控制碼的回呼函式可以存取此資料。 如果架構正在同步處理對驅動程式回呼函式的呼叫,一次只會呼叫一個回呼函式,而且物件的內容空間一次只能存取一個回呼函式。
除非您的驅動程式實作 被動層級中斷處理,否則服務中斷和存取中斷資料的程式碼必須在裝置的 IRQL (DIRQL) 執行,而且需要額外的同步處理。 如需詳細資訊,請參閱 同步處理中斷程式碼。
如果您的驅動程式啟用自動同步處理處理 I/O 要求的回呼函式,架構會同步處理這些回呼函式,以便一次執行一個回呼函式。 下表列出架構同步處理的回呼函式。
物件型別 | 同步處理的回呼函式 |
---|---|
Queue 物件 |
|
File 物件 |
所有 回呼函式 |
要求物件 |
或者,架構也可以將這些回呼函式與驅動程式提供給裝置的任何中斷、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。
如果您想要架構為所有裝置提供裝置層級同步處理,您可以使用下列步驟:
在驅動程式驅動程式物件的WDF_OBJECT_ATTRIBUTES結構中,將SynchronizationScope設定為WdfSynchronizationScopeDevice。
針對每個裝置物件使用預設的 WdfSynchronizationScopeInheritFromParent值。
或者,若要提供個別裝置的裝置層級同步處理,您可以使用下列步驟:
使用驅動程式物件的預設WdfSynchronizationScopeNone值。
將SynchronizationScope設定為個別裝置物件WDF_OBJECT_ATTRIBUTES結構中的WdfSynchronizationScopeDevice。
如果您想要架構為裝置提供佇列層級同步處理,可以使用下列技術:
針對架構 1.9 版和更新版本,您應該在佇列物件的WDF_OBJECT_ATTRIBUTES結構中設定WdfSynchronizationScopeQueue,以啟用個別佇列的佇列層級同步處理。 這是慣用的技術。
或者,您可以在所有架構版本中使用下列步驟:
- 在裝置物件的WDF_OBJECT_ATTRIBUTES結構中,將SynchronizationScope設定為WdfSynchronizationScopeQueue。
- 針對每個裝置的佇列物件使用預設WdfSynchronizationScopeInheritFromParent值。
如果您不想讓架構同步處理處理驅動程式 I/O 要求的回呼函式,請使用驅動程式驅動程式、裝置和佇列物件的預設 SynchronizationScope 值。 在此情況下,架構不會自動同步驅動程式的 I/O 要求相關回呼函式,而且可以在 IRQL < = DISPATCH_LEVEL呼叫回呼函式。
請注意,設定 SynchronizationScope 值只會同步處理上表所包含的回呼函式。 如果您想要架構也同步處理驅動程式的中斷、DPC、工作專案和計時器物件回呼函式,驅動程式必須將這些物件的組態結構的 AutomaticSerialization 成員設定為 TRUE。
不過,只有當您想要同步處理的所有回呼函式都在同一 IRQL 上執行時,才可以將 AutomaticSerialization 設定為 TRUE 。 選擇下一個描述的執行 層級可能會導致 IRQL 層級不相容。 在這種情況下,驅動程式必須使用 架構鎖定 ,而不是設定 AutomaticSerialization。 如需中斷、DPC、工作專案和計時器物件之組態結構的詳細資訊,以及這些結構中設定 AutomaticSerialization 的限制詳細資訊,請參閱 WDF_INTERRUPT_CONFIG、 WDF_DPC_CONFIG、 WDF_WORKITEM_CONFIG和 WDF_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 |
您可以將驅動程式、裝置、檔案、佇列、計時器和一般物件的執行層級設定為 WdfExecutionLevelPassive 或 WdfExecutionLevelDispatch 。 對於其他物件,只允許 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。