Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Téměř veškerý kód v ovladači založeném na rozhraní se nachází ve funkcích zpětného volání událostí. Architektura automaticky synchronizuje většinu funkcí zpětného volání ovladače následujícím způsobem:
Architektura vždy synchronizuje funkce zpětného volání událostí obecného objektu zařízení, funkčního objektu zařízení (FDO) a fyzického objektu zařízení (PDO) mezi sebou. Pro každé zařízení je možné volat vždy jenom jednu z funkcí zpětného volání. Výjimkou je EvtDeviceSurpriseRemoval, EvtDeviceQueryRemove a EvtDeviceQueryStop. Tyto funkce zpětného volání podporují Plug and Play (PnP) a události řízení spotřeby a volají se na úrovni IRQL = PASSIVE_LEVEL.
Volitelně může architektura synchronizovat provádění funkcí zpětného volání, které zpracovávají vstupně-výstupní požadavky ovladače, aby tyto funkce zpětného volání běžely po jednom. Konkrétně může rozhraní synchronizovat funkce zpětného volání pro frontu, přerušení, volání odloženého postupu (DPC), časovač, pracovní položky, a objekty souborů, spolu se zpětným voláním objektu požadavku pomocí funkce EvtRequestCancel. Architektura volá většinu těchto funkcí zpětného volání v IRQL = DISPATCH_LEVEL, ale můžete vynutit, aby funkce zpětného volání objektu fronty a souboru běžely v IRQL = PASSIVE_LEVEL. (Funkce zpětného volání pracovních položek se vždy spouštějí na PASSIVE_LEVEL.)
Architektura implementuje tuto automatickou synchronizaci pomocí sady interních zámků synchronizace. Architektura zajišťuje, že dvě nebo více vláken nemůže současně volat stejnou funkci zpětného volání. Každé vlákno musí počkat, až získá zámek synchronizace před voláním funkce zpětného volání. (Volitelně můžou ovladače tyto zámky synchronizace získat i v případě potřeby. Další informace naleznete v tématu Použití zámků architektury.)
Ovladač by měl ukládat data specifická pro objekty v kontextovém prostoru objektu. Pokud váš ovladač používá pouze rozhraní definovaná architekturou, můžou k datům přistupovat pouze funkce zpětného volání, které obdrží popisovač objektu. Pokud architektura synchronizuje volání funkcí zpětného volání ovladače, volá se současně pouze jedna funkce zpětného volání. Kontextový prostor objektu je přístupný pouze pro jednu funkci zpětného volání najednou.
Pokud ovladač neimplementuje zpracování přerušení na pasivní úrovni, kód, který služby přeruší a přistupuje k datům přerušení, musí běžet v IRQL (DIRQL) zařízení a vyžaduje další synchronizaci. Další informace naleznete v tématu Synchronizace kódu přerušení.
Pokud ovladač umožňuje automatickou synchronizaci funkcí zpětného volání, které zpracovávají vstupně-výstupní požadavky, architektura synchronizuje tyto funkce zpětného volání tak, aby běžely po jednom. Následující tabulka uvádí funkce zpětného volání, které architektura synchronizuje.
| Typ objektu | Synchronizované funkce zpětného volání |
|---|---|
Objekt fronty |
Obslužné rutiny žádostí, EvtIoQueueState, EvtIoResume, EvtIoStop |
Objekt souboru |
Všechny funkce zpětného volání |
Objekt požadavku |
Volitelně může rozhraní také synchronizovat funkce zpětného volání s libovolnými funkcemi objektu přerušení, DPC, pracovní položky a časovače, které ovladač poskytuje pro zařízení (s výjimkou zpětného volání EvtInterruptIsr objektu přerušení). Aby bylo možné tuto další synchronizaci povolit, musí ovladač nastavit člen AutomaticSerialization struktury konfigurace těchto objektů na HODNOTU TRUE.
V souhrnu poskytuje funkce automatické synchronizace architektury následující funkce:
Architektura vždy synchronizuje funkce zpětného volání PnP a řízení spotřeby každého zařízení.
Volitelně může architektura synchronizovat obslužné rutiny žádostí ve frontě vstupně-výstupních operací a několik dalších funkcí zpětného volání (viz předchozí tabulka).
Ovladač může požádat architekturu o synchronizaci funkcí zpětného volání pro přerušení, DPC, pracovní položku a objekty časovače.
Ovladače musí synchronizovat kód, který servisuje přerušení a přistupuje k datům přerušení pomocí technik popsaných v Synchronizace kódu přerušení.
Rámec nesynchronizuje jiné funkce zpětného volání ovladače, jako je funkce zpětného volání CompletionRoutine nebo funkce zpětného volání, které definuje objekt cíle I/O operací. Místo toho architektura poskytuje další zámky , které můžou ovladače použít k synchronizaci těchto funkcí zpětného volání.
Volba oboru synchronizace
Můžete zvolit, aby architektura synchronizovala všechny funkce zpětného volání, které jsou přidružené ke všem vstupně-výstupním frontám zařízení. Alternativně můžete zvolit, že architektura bude samostatně synchronizovat funkce zpětného volání pro každou z vstupně-výstupních front zařízení. Možnosti synchronizace, které jsou pro ovladač k dispozici, jsou následující:
Synchronizace na úrovni zařízení
Framework synchronizuje funkce zpětného volání ve všech I/O frontách zařízení, takže běží postupně po jedné. Architektura tuto synchronizaci dosahuje získáním zámku synchronizace zařízení před voláním funkce zpětného volání.
Synchronizace na úrovni fronty
Rámec synchronizuje funkce zpětného volání pro každou jednotlivou I/O frontu, takže budou spuštěny jeden po druhém. Architektura tuto synchronizaci dosahuje získáním zámku synchronizace fronty před voláním funkce zpětného volání.
Žádná synchronizace
Architektura nesynchronizuje provádění funkcí zpětného volání v předchozí tabulce a před voláním funkcí zpětného volání nezíská zámek synchronizace. Pokud je vyžadována synchronizace, ovladač ji musí poskytnout.
Pokud chcete určit, jestli má architektura poskytovat synchronizaci na úrovni zařízení, synchronizaci na úrovni fronty nebo žádnou synchronizaci ovladače, zadejte obor synchronizace pro objekt ovladače, objekty zařízení nebo objekty fronty. Člen SynchronizationScopeWDF_OBJECT_ATTRIBUTES struktury objektu identifikuje rozsah synchronizace objektu. Hodnoty oboru synchronizace, které může ovladač zadat, jsou:
WdfSynchronizationScopeDevice
Architektura se synchronizuje získáním zámku synchronizace objektu zařízení.
WdfSynchronizationScopeQueue
Architektura se synchronizuje získáním zámku synchronizace objektu fronty.
WdfSynchronizationScopeNone
Framework se nesynchronizuje a nezíská zámek synchronizace.
WdfSynchronizationScopeInheritFromParent
Rozhraní získá hodnotu SynchronizationScope objektu z nadřazeného objektu.
Obecně platí, že nepoužívejte synchronizaci na úrovni zařízení.
Další informace o hodnotách oboru synchronizace najdete v tématu WDF_SYNCHRONIZATION_SCOPE.
Výchozí obor synchronizace pro objekty ovladače je WdfSynchronizationScopeNone. Výchozí obor synchronizace pro objekty zařízení a fronty je WdfSynchronizationScopeInheritFromParent.
Chcete-li použít architekturu k zajištění synchronizace na úrovni zařízení pro všechna zařízení, nastavte SynchronizationScope na WdfSynchronizationScopeDevice ve struktuře WDF_OBJECT_ATTRIBUTESobjektu ovladače . Pro každý objekt zařízení použijte výchozí hodnotu WdfSynchronizationScopeInheritFromParent.
Pokud chcete poskytnout synchronizaci na úrovni zařízení pro jednotlivá zařízení, použijte výchozí hodnotu WdfSynchronizationScopeNone pro objekt ovladače . Nastavte SynchronizationScope na WdfSynchronizationScopeDevice ve WDF_OBJECT_ATTRIBUTES struktuře jednotlivých objektů zařízení .
Pokud chcete, aby architektura poskytovala synchronizaci na úrovni fronty pro zařízení, můžete použít následující techniky:
Pro rozhraní verze 1.9 a novější povolte synchronizaci na úrovni fronty pro jednotlivé fronty nastavením WdfSynchronizationScopeQueue ve struktuře WDF_OBJECT_ATTRIBUTES objektu fronty. Tato technika je upřednostňovaná.
Alternativně můžete ve všech verzích architektury použít následující kroky:
- Nastavte SynchronizationScope na WdfSynchronizationScopeQueue ve struktuře WDF_OBJECT_ATTRIBUTESobjektu zařízení .
- U každého zařízení použijte výchozí hodnotu WdfSynchronizationScopeInheritFromParent pro objekty fronty.
Pokud nechcete, aby framework synchronizoval funkce zpětného volání, které zpracovávají vstupně-výstupní požadavky vašeho ovladače, použijte výchozí hodnotu SynchronizationScope pro objekty ovladače, zařízení a fronty. V tomto případě architektura automaticky nesynchronizuje funkce zpětného volání související s požadavky ovladače. Architektura může volat funkce zpětného volání v IRQL <= DISPATCH_LEVEL.
Nastavení hodnoty SynchronizationScope synchronizuje pouze funkce zpětného volání, které předchozí tabulka obsahuje. Chcete-li, aby framework také synchronizoval přerušení ovladače, DPC, pracovní položky a funkce zpětného volání objektů časovače, nastavte člen AutomaticSerialization v konfiguračních strukturách těchto objektů na TRUE.
Funkci AutomaticSerialization však můžete nastavit na hodnotu TRUE pouze v případě, že všechny funkce zpětného volání, které chcete synchronizovat, se spouštějí ve stejném prostředí IRQL. Volba úrovně provádění, která je popsána dále, může vést k nekompatibilním úrovním IRQL. V takové situaci musí ovladač místo nastavení AutomatickéSerializace používat rámcové zámky. Další informace o strukturách konfigurace pro přerušení, DPC, pracovní položky a objekty časovače a další informace o omezeních, která platí pro nastavení AutomatickéSerializace v těchto strukturách, najdete v tématu WDF_INTERRUPT_CONFIG, WDF_DPC_CONFIG, WDF_WORKITEM_CONFIG a WDF_TIMER_CONFIG.
Pokud nastavíte automatickou serializaci na hodnotu TRUE, vyberte synchronizaci na úrovni fronty.
Volba úrovně provádění
Když ovladač vytvoří některé typy objektů architektury, může určit úroveň provádění objektu. Úroveň provádění určuje IRQL, ve které architektura volá funkce zpětného volání událostí objektu, které zpracovávají vstupně-výstupní požadavky ovladače.
Pokud ovladač poskytuje úroveň provádění, zadaná úroveň ovlivní funkce zpětného volání pro objekty fronty a souboru. Obvykle platí, že pokud ovladač používá automatickou synchronizaci, architektura volá tyto funkce zpětného volání v IRQL = DISPATCH_LEVEL. Nastavením úrovně provádění může ovladač vynutit, aby rámec volal tyto zpětné funkce při IRQL = PASSIVE_LEVEL. Architektura používá následující pravidla při nastavování IRQL, při kterém volá funkce zpětného volání fronty a objektu souboru:
Pokud ovladač používá automatickou synchronizaci, volá framework jeho funkce zpětného volání fronty a objektu souboru na úrovni IRQL = DISPATCH_LEVEL, pokud ovladač nepožádá framework, aby tyto funkce volal na úrovni IRQL = PASSIVE_LEVEL.
Pokud ovladač nepoužívá automatickou synchronizaci a nezadá úroveň provádění, může rozhraní volat funkce zpětného volání fronty ovladače a objektu souboru při IRQL <= DISPATCH_LEVEL.
Pokud ovladač poskytuje funkce zpětného volání objektu souboru, pravděpodobně chcete, aby architektura volala tyto funkce zpětného volání v IRQL = PASSIVE_LEVEL, protože některá data souboru, například název souboru, je stránkovatelná.
Chcete-li zadat úroveň provádění, ovladač musí zadat hodnotu pro ExecutionLevel člen objektu WDF_OBJECT_ATTRIBUTES struktury. Hodnoty na úrovni spuštění, které může ovladač zadat, jsou:
WdfExecutionLevelPassive
Rámec volá zpětné volání funkcí objektu na úrovni IRQL = PASSIVE_LEVEL.
WdfExecutionLevelDispatch
Rámec může volat funkce zpětného volání objektu na úrovni IRQL <= DISPATCH_LEVEL. Pokud ovladač používá automatickou synchronizaci, framework vždy volá funkce zpětného volání na úrovni IRQL = DISPATCH_LEVEL.
WdfExecutionLevelInheritFromParent
Rozhraní získá hodnotu ExecutionLevel objektu z nadřazeného objektu.
Výchozí úroveň spuštění pro objekty ovladače je WdfExecutionLevelDispatch. Výchozí úroveň spuštění pro všechny ostatní objekty je WdfExecutionLevelInheritFromParent.
Další informace o hodnotách na úrovni provádění najdete v tématu WDF_EXECUTION_LEVEL.
Následující tabulka ukazuje úroveň IRQL, při které může rámec volat callback funkce ovladače pro frontové objekty a souborové objekty.
| Rozsah synchronizace | Úroveň provádění | IRQL funkcí zpětného volání fronty a souborů |
|---|---|---|
WdfSynchronizationScopeDevice |
WdfExecutionLevelPassive |
PASSIVE_LEVEL |
WdfSynchronizationScopeDevice |
WdfExecutionLevelDispatch |
DISPATCH_LEVEL |
WdfSynchronizationScopeQueue |
WdfExecutionLevelPassive |
PASSIVE_LEVEL |
WdfSynchronizationScopeQueue |
WdfExecutionLevelDispatch |
Úroveň správy |
WdfSynchronizationScopeNone |
WdfExecutionLevelPassive |
PASSIVE_LEVEL |
WdfSynchronizationScopeNone |
WdfExecutionLevelDispatch |
<= DISPATCH_LEVEL |
Úroveň spuštění můžete nastavit na WdfExecutionLevelPassive nebo WdfExecutionLevelDispatch pro ovladač, zařízení, soubor, frontu, časovač a obecné objekty. U jiných objektů můžete nastavit pouze WdfExecutionLevelInheritFromParent.
Zadejte WdfExecutionLevelPassive , pokud:
Funkce zpětného volání ovladače musí volat metody rozhraní nebo rutiny WDM (Windows Driver Model), které lze volat pouze v IRQL = PASSIVE_LEVEL.
Funkce zpětného volání ovladače musí přistupovat ke stránkovatelnému kódu nebo datům. Například funkce zpětného volání objektu souboru obvykle přistupuje k stránkovatelným datům.
Místo nastavení WdfExecutionLevelPassive může ovladač nastavit WdfExecutionLevelDispatch a poskytnout funkci zpětného volání, která vytvoří pracovní položky , pokud musí zpracovat některé operace v IRQL = PASSIVE_LEVEL.
Než se rozhodnete, jestli má ovladač nastavit úroveň spuštění objektu na WdfExecutionLevelPassive, určete IRQL, na které se ovladač a další ovladače v zásobníku ovladačů volají. Vezměte v úvahu následující situace:
Pokud je ovladač v horní části zásobníku ovladačů v režimu kernelu, systém obvykle volá ovladač na IRQL = PASSIVE_LEVEL. Klientem takového ovladače může být ovladač založený na UMDF nebo aplikace v uživatelském režimu. Určení WdfExecutionLevelPassive nemá nepříznivý vliv na výkon ovladače, protože rámec nemusí zařazovat volání vašeho ovladače do fronty pracovních položek, které se volají na IRQL = PASSIVE_LEVEL.
Pokud váš ovladač není v horní části zásobníku volání, systém pravděpodobně nevolá váš ovladač na úrovni IRQL = PASSIVE_LEVEL. Proto musí framework zařadit volání vašeho ovladače do fronty na pracovní úlohy, které jsou následně volány na úrovni IRQL = PASSIVE_LEVEL. Tento proces může způsobit špatný výkon ovladače ve srovnání s povolením, aby funkce zpětného volání vašeho ovladače byly volány na IRQL <= DISPATCH_LEVEL.
U objektů DPC a pro objekty časovače, které nepředstavují časovače pasivní úrovně, nelze nastavit člen AutomaticSerialization struktury konfigurace na HODNOTU TRUE , pokud nastavíte úroveň spouštění nadřazeného zařízení na WdfExecutionLevelPassive. Architektura získá zámky synchronizace zpětného volání objektu zařízení na úrovni IRQL = PASSIVE_LEVEL. Proto nemůže použít zámky k synchronizaci funkcí zpětného volání objektu DPC nebo časovače, které musí být spuštěny v IRQL = DISPATCH_LEVEL. V takovém případě by ovladač měl používat zamykání architektury v libovolném zařízení, DPC nebo funkcích zpětného volání objektu časovače, které se musí vzájemně synchronizovat.
Všimněte si také, že pro objekty časovače, které představují pasivní úrovně časovače, můžete nastavit člen AutomaticSerialization struktury konfigurace na TRUE pouze v případě, že úroveň spouštění nadřazeného zařízení je nastavena na WdfExecutionLevelPassive.