工作專案 是驅動程式在 EvtWorkItem 事件回呼函式中執行的工作。 這些函數會在系統工作執行緒的內容中,以異步方式在 IRQL = PASSIVE_LEVEL 執行。
框架型驅動程式通常會使用工作專案,當函式 EvtInterruptDpc 或 EvtDpcFunc 在 IRQL = DISPATCH_LEVEL 執行時,必須在 IRQL = PASSIVE_LEVEL 執行額外的處理。
換句話說,如果有一個函式在 IRQL = DISPATCH_LEVEL 執行而需要呼叫一個只能在 IRQL = PASSIVE_LEVEL 呼叫的函式,那麼驅動程式可以使用工作項目。
一般而言,驅動程式的 EvtInterruptDpc 或 EvtDpcFunc 回呼函式會建立工作項目物件,並將它新增至系統的工作專案佇列。 之後,系統背景工作線程會清除佇列物件,並呼叫工作專案的 EvtWorkItem 回呼函式。
使用工作項目的範例驅動程式
使用工作專案的範例架構驅動程式 包括 1394、AMCC5933、PCIDRV 和烤箱。
設定工作項目
若要設定工作項目,您的驅動程式必須:
建立工作專案。
您的驅動程式會呼叫 WdfWorkItemCreate 來建立工作項目物件,並識別將處理工作專案的 EvtWorkItem 回呼函式。
儲存工作項目的相關信息。
一般而言,驅動程式會使用工作專案物件的內容記憶體來儲存有關任務的資訊,EvtWorkItem 回呼函式應該執行。 呼叫 EvtWorkItem 回呼函式時,可以藉由存取此內容記憶體來擷取資訊。 如需如何配置和存取內容記憶體的資訊,請參閱 Framework 物件內容空間。
將工作專案新增至系統的工作專案佇列。
您的驅動程式會呼叫 WdfWorkItemEnqueue,這會將驅動程式的工作專案新增至工作專案佇列。
當驅動程式呼叫 WdfWorkItemCreate時,必須提供架構設備物件或架構佇列物件的控制項。 當系統刪除該物件時,它也會刪除與 對象相關聯的任何現有工作專案。 系統會釋放工作項目物件,並在叫用父物件的 EvtCleanupCallback 回呼函式之前整理其相關聯的工作專案回呼函式。
如需架構物件階層清除規則的詳細資訊,請參閱 Framework 物件生命週期。
使用 Work-Item 回呼函式
將工作專案新增至工作專案佇列之後,它會保留在佇列中,直到系統背景工作線程變成可用為止。 系統工作執行緒會從佇列中移除工作項目,然後呼叫驅動程式的 EvtWorkItem 回呼函式,作為輸入傳遞工作項目物件。
一般而言,EvtWorkItem 回呼函式會執行下列步驟:
藉由存取工作專案對象的內容記憶體,取得工作專案的相關驅動程式提供的資訊。
執行您指定的工作。 如有必要,回呼函式可以呼叫 WdfWorkItemGetParentObject 來判斷工作專案的父物件。
呼叫 WdfObjectDelete 來刪除工作項物件,或者,如果驅動程式將會重新排入工作項目佇列,則表示該工作項目的句柄現在可以重複使用。
每個工作項目的回呼函式所執行的任務必須要相對地簡短。 作業系統會提供有限的系統工作線程,因此如果驅動程式使用工作項目回呼函式來執行耗時的任務,您的驅動程式可能會妨礙系統效能。
建立和刪除工作專案
驅動程式可以使用下列兩種技術之一來建立和刪除工作專案:
使用每個工作專案一次:在需要時建立工作專案,並在使用后立即將其刪除。
這項技術適用於那些需要很少使用(每分鐘少於一次)少量工作項目的驅動程式。
例如,驅動程式的 EvtInterruptDpc 回呼函式可以呼叫 WdfWorkItemCreate,然後 WdfWorkItemEnqueue,而工作專案的 EvtWorkItem 回呼函式可以呼叫 WdfObjectDelete。
如果您的驅動程式遵循此案例,而且如果其 EvtInterruptDpc 回呼函式 STATUS_INSUFFICIENT_RESOURCES收到 WdfWorkItemCreate傳回值,則驅動程式必須能夠延後所需的工作,直到系統資源(通常是記憶體)變成可用為止。
建立一或多個工作專案,讓驅動程式在需要時重新排回佇列。
這項技術適用於經常使用工作項目的驅動程式(每分鐘超過一次),或者,如果驅動程式的 EvtInterruptDpc 回呼函式無法輕易處理 WdfWorkItemCreate的STATUS_INSUFFICIENT_RESOURCES傳回值。
系統不會將工作線程配置給工作專案,直到驅動程式呼叫 WdfWorkItemEnqueue。 因此,即使系統背景工作線程是有限的資源,在初始化裝置時建立工作專案會耗用少量的記憶體,但不會影響系統效能。
下列步驟描述可能的案例:
- 驅動程式的 EvtDriverDeviceAdd 回呼函式會呼叫 WdfWorkItemCreate,以取得工作專案控制代碼。
- 驅動程式的 EvtInterruptDpc 回呼函式會建立一個EvtWorkItem 回呼函式必須執行的動作清單,然後使用步驟 1 中的控制代碼呼叫 WdfWorkItemEnqueue。
- 驅動程式的 EvtWorkItem 回呼函式會執行動作清單,並設定旗標來指出回呼函式已執行。
之後,每次呼叫驅動程式的 EvtInterruptDpc 回呼函式時,都必須判斷是否已執行 EvtWorkItem 回呼函式。 如果 EvtWorkItem 回呼函式尚未執行,EvtInterruptDpc 回呼函式不會呼叫 WdfWorkItemEnqueue,因為工作專案仍會排入佇列。 在此情況下,EvtInterruptDpc 回呼函式只會更新 EvtWorkItem 回呼函式的動作清單。
每個工作項目都會與裝置或佇列相關聯。 移除相關聯的裝置或佇列時,架構會刪除所有相關聯的工作專案,因此如果您使用這項技術,驅動程式不需要呼叫 WdfObjectDelete。
少數驅動程式可能需要呼叫 WdfWorkItemFlush,以從工作專案佇列排清其工作專案。 如需使用 WdfWorkItemFlush的範例,請參閱 方法的參考頁面。
如果驅動程式在未完成的工作專案上呼叫 WdfObjectDelete,則結果取決於工作項目的狀態:
| 工作項目狀態 | 結果 |
|---|---|
| 已建立但未加入佇列 | 工作項目會立即清理。 |
| 加入佇列 | 呼叫 WdfObjectDelete 等候工作專案完成執行,然後清除工作專案 |
| 執行 | 如果驅動程式從 EvtWorkItem 內部呼叫 WdfObjectDelete,則 WdfObjectDelete 會立即返回。 一旦 EvtWorkItem 完成,該工作項目將被清除。 否則,WdfObjectDelete 等候 EvtWorkItem 完成。 |