Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować się zalogować lub zmienić katalog.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Prawie cały kod w sterowniku opartym na frameworku znajduje się w funkcjach zwrotnego wywołania zdarzeń. Framework automatycznie synchronizuje większość funkcji wywołania zwrotnego sterownika w sposób przedstawiony poniżej:
Struktura zawsze synchronizuje ogólny obiekt urządzenia, funkcjonalny obiekt urządzenia (FDO) i funkcje wywołania zwrotnego zdarzeń obiektu urządzenia fizycznego (PDO). Tylko jedna z funkcji wywołania zwrotnego może być wywoływana jednocześnie dla każdego urządzenia. Wyjątkiem są EvtDeviceSurpriseRemoval, EvtDeviceQueryRemove i EvtDeviceQueryStop. Te funkcje wywołania zwrotnego obsługują zdarzenia Plug and Play (PnP) i zarządzania energią oraz są wywoływane na poziomie IRQL = PASSIVE_LEVEL.
Opcjonalnie platforma może zsynchronizować wykonywanie funkcji wywołania zwrotnego, które obsługują żądania we/wy sterownika, aby te funkcje wywołania zwrotnego były uruchamiane pojedynczo. W szczególności platforma może synchronizować funkcje wywołania zwrotnego dla kolejki, przerwania, procedury odroczonej (DPC), timera, elementu roboczego i obiektów pliku, wraz z funkcją wywołania zwrotnego dla obiektu żądania EvtRequestCancel. Framework wywołuje większość tych funkcji wywołania zwrotnego na poziomie IRQL = DISPATCH_LEVEL, ale można wymusić uruchamianie funkcji wywołania zwrotnego dla obiektów kolejki i plików na poziomie IRQL = PASSIVE_LEVEL. (Funkcje wywołania zwrotnego elementów roboczych są zawsze uruchamiane w PASSIVE_LEVEL).
Struktura implementuje tę automatyczną synchronizację przy użyciu zestawu blokad synchronizacji wewnętrznej. Platforma zapewnia, że co najmniej dwa wątki nie mogą jednocześnie wywoływać tej samej funkcji wywołania zwrotnego. Każdy wątek musi czekać, aż uzyska blokadę synchronizacji przed wywołaniem funkcji wywołania zwrotnego. (Opcjonalnie, sterowniki mogą również uzyskać te blokady synchronizacji w razie potrzeby. Aby uzyskać więcej informacji, zobacz Using Framework Locks.)
Sterownik powinien przechowywać dane specyficzne dla obiektu w przestrzeni kontekstowej obiektu. Jeśli sterownik używa tylko interfejsów zdefiniowanych przez platformę, tylko funkcje wywołania zwrotnego, które odbierają dojście do obiektu, mogą uzyskiwać dostęp do tych danych. Jeśli struktura synchronizuje wywołania funkcji zwrotnych sterownika, w danym momencie wywoływana jest tylko jedna taka funkcja. Przestrzeń kontekstowa obiektu jest dostępna tylko dla jednej funkcji wywołania zwrotnego jednocześnie.
Jeśli sterownik nie implementuje obsługi przerwań na poziomie pasywnym, kod, który przerywa działanie usług i uzyskuje dostęp do danych przerwań, musi działać w środowisku IRQL (DIRQL) urządzenia i wymaga dodatkowej synchronizacji. Aby uzyskać więcej informacji, zobacz Synchronizowanie kodu przerwania.
Jeśli sterownik włączy automatyczną synchronizację funkcji wywołania zwrotnego, które obsługują żądania we/wy, platforma synchronizuje te funkcje wywołania zwrotnego, tak aby były uruchamiane pojedynczo. W poniższej tabeli wymieniono funkcje wywołania zwrotnego synchronizowane przez strukturę.
| Typ obiektu | Zsynchronizowane funkcje wywołania zwrotnego |
|---|---|
Obiekt kolejki |
Programy obsługi żądań, EvtIoQueueState, EvtIoResume, EvtIoStop |
Obiekt pliku |
Wszystkie funkcje wywołania zwrotnego |
Obiekt żądania |
Opcjonalnie struktura może również synchronizować te funkcje wywołania zwrotnego z dowolnym przerwaniem, DPC, elementem roboczym i obiektem czasomierza, które sterownik udostępnia dla urządzenia (z wyłączeniem funkcji wywołania zwrotnego obiektu przerwania EvtInterruptIsr). Aby włączyć tę dodatkową synchronizację, sterownik musi ustawić członka AutomaticSerialization struktur konfiguracji tych obiektów na TRUE.
Podsumowując, funkcja automatycznej synchronizacji platformy udostępnia następujące funkcje:
Framework zawsze synchronizuje funkcje PnP i zarządzania energią poszczególnych urządzeń.
Opcjonalnie platforma może synchronizować procedury obsługi żądań kolejki we/wy i kilka dodatkowych funkcji wywołania zwrotnego (zobacz poprzednią tabelę).
Sterownik może poprosić platformę o zsynchronizowanie funkcji wywołania zwrotnego dla obiektów przerwania, DPC, elementu roboczego i czasomierza.
Sterowniki muszą synchronizować kod, który obsługuje przerwania i uzyskuje dostęp do danych przerwania, korzystając z technik opisanych w sekcji Synchronizowanie kodu przerwania.
Struktura nie synchronizuje innych funkcji wywołania zwrotnego sterownika, takich jak funkcja wywołania zwrotnego CompletionRoutine sterownika lub funkcje wywołania zwrotnego zdefiniowane przez obiekt docelowy I/O. Zamiast tego, struktura udostępnia dodatkowe blokady, których sterowniki mogą używać do synchronizowania tych funkcji wywołania zwrotnego.
Wybieranie zakresu synchronizacji
Możesz wybrać, że platforma synchronizuje wszystkie funkcje wywołania zwrotnego skojarzone ze wszystkimi kolejkami we/wy urządzenia. Alternatywnie możesz wybrać, aby ramy oddzielnie synchronizowały funkcje wywołań zwrotnych dla każdej kolejki we/wy urządzenia. Opcje synchronizacji dostępne dla sterownika są następujące:
Synchronizacja na poziomie urządzenia
System synchronizuje funkcje zwrotne dla wszystkich kolejek I/O urządzenia, tak aby były uruchamiane jedna po drugiej. Struktura osiąga tę synchronizację, uzyskując blokadę synchronizacji urządzenia przed wywołaniem procedury zwrotnej.
Synchronizacja na poziomie kolejki
Framework synchronizuje funkcje wywołania zwrotnego dla każdej pojedynczej kolejki I/O, więc są uruchamiane pojedynczo. Framework osiąga tę synchronizację poprzez uzyskanie blokady synchronizacji kolejki przed wywołaniem funkcji callback.
Brak synchronizacji
Framework nie synchronizuje wykonywania funkcji zwrotnych w poprzedniej tabeli i nie uzyskuje blokady synchronizacyjnej przed ich wywołaniem. Jeśli wymagana jest synchronizacja, sterownik musi ją zapewnić.
Aby określić, czy struktura ma zapewnić synchronizację na poziomie urządzenia, synchronizację na poziomie kolejki, czy też brak synchronizacji dla sterownika, określ zakres synchronizacji dla obiektu sterownika, obiektów urządzeń lub obiektów kolejek. Składowa SynchronizationScope struktury WDF_OBJECT_ATTRIBUTES obiektu identyfikuje zakres synchronizacji obiektu. Wartości zakresu synchronizacji, które może określić sterownik, to:
WdfSynchronizationScopeDevice
Struktura jest synchronizowana przez uzyskanie blokady synchronizacji obiektu urządzenia.
WdfSynchronizationScopeQueue
Framework synchronizuje się, uzyskując blokadę synchronizacji obiektu w kolejce.
WdfSynchronizationScopeNone
Platforma nie synchronizuje się i nie uzyskuje blokady synchronizacji.
WdfSynchronizationScopeInheritFromParent
Struktura uzyskuje wartość SynchronizationScope obiektu z jego obiektu nadrzędnego.
Ogólnie rzecz biorąc, unikaj synchronizacji na poziomie urządzenia.
Aby uzyskać więcej informacji na temat wartości zakresu synchronizacji, zobacz WDF_SYNCHRONIZATION_SCOPE.
Domyślny zakres synchronizacji obiektów sterowników to WdfSynchronizationScopeNone. Domyślny zakres synchronizacji dla obiektów urządzeń i kolejek to WdfSynchronizationScopeInheritFromParent.
Aby użyć struktury do zapewnienia synchronizacji na poziomie urządzenia dla wszystkich urządzeń, ustaw parametr SynchronizationScope na WdfSynchronizationScopeDevice w strukturze WDF_OBJECT_ATTRIBUTES obiektu sterownika. Użyj domyślnej wartości WdfSynchronizationScopeInheritFromParent dla każdego obiektu urządzenia .
Aby zapewnić synchronizację na poziomie urządzenia dla poszczególnych urządzeń, użyj domyślnej wartości WdfSynchronizationScopeNone dla obiektu sterownika . Ustaw właściwość SynchronizationScope na WdfSynchronizationScopeDevice w WDF_OBJECT_ATTRIBUTES strukturze poszczególnych obiektów urządzeń .
Jeśli chcesz, aby struktura zapewniała synchronizację na poziomie kolejki dla urządzenia, możesz użyć następujących technik:
W przypadku platformy w wersji 1.9 lub nowszej włącz synchronizację na poziomie kolejki dla poszczególnych kolejek, ustawiając WdfSynchronizationScopeQueue w strukturze WDF_OBJECT_ATTRIBUTES obiektu kolejki. Ta technika jest preferowana.
Alternatywnie możesz użyć następujących kroków we wszystkich wersjach platformy:
- Ustaw właściwość SynchronizationScope na WdfSynchronizationScopeQueue w strukturze WDF_OBJECT_ATTRIBUTES obiektu urządzenia .
- Użyj domyślnej wartości WdfSynchronizationScopeInheritFromParent dla obiektów kolejki każdego urządzenia.
Jeśli nie chcesz, aby platforma synchronizowała funkcje wywołania zwrotnego obsługujące żądania we/wy Twojego sterownika, użyj domyślnej wartości SynchronizationScope dla obiektów sterownika, urządzenia i kolejki. W takim przypadku framework nie synchronizuje automatycznie funkcji wywołania zwrotnego związanych z żądaniami I/O sterownika. Framework może wywoływać funkcje zwrotne w środowisku IRQL <= DISPATCH_LEVEL.
Ustawienie wartości SynchronizationScope synchronizuje tylko funkcje wywołania zwrotnego, które zawiera poprzednia tabela. Jeśli chcesz, aby platforma również synchronizowała przerwania sterownika, DPC, element zadania roboczego i funkcje wywołania zwrotnego obiektów czasomierza, ustaw członek AutomaticSerialization w strukturach konfiguracji tych obiektów na TRUE.
Można jednak ustawić wartość AutomaticSerialization na wartość TRUE tylko wtedy, gdy wszystkie funkcje wywołania zwrotnego, które chcesz zsynchronizować, są uruchamiane w tym samym środowisku IRQL. Wybranie poziomu wykonywania opisanego w dalszej kolejności może spowodować niezgodność poziomów IRQL. W takiej sytuacji sterownik musi używać blokad systemowych zamiast ustawiania AutomatycznejSerializacji. Aby uzyskać więcej informacji na temat struktur konfiguracji przerwań, DPC, przedmiotów roboczych i obiektów czasomierzy oraz aby uzyskać więcej informacji na temat ograniczeń dotyczących ustawiania automatycznej seryzacji w tych strukturach, zobacz WDF_INTERRUPT_CONFIG, WDF_DPC_CONFIG, WDF_WORKITEM_CONFIG i WDF_TIMER_CONFIG.
Jeśli ustawisz wartość AutomaticSerialization na TRUE, wybierz pozycję Synchronizacja na poziomie kolejki.
Wybieranie poziomu wykonywania
Gdy sterownik tworzy niektóre typy obiektów struktury, może określić poziom wykonywania dla obiektu. Poziom wykonywania określa poziom IRQL, na którym struktura wywołuje funkcje obsługi zdarzeń obiektu, które dotyczą żądań we/wy sterownika.
Jeśli sterownik określa poziom wykonania, podany poziom wpływa na funkcje wywołania zwrotnego dla obiektów kolejki i plików. Zwykle, jeśli sterownik korzysta z automatycznej synchronizacji, framework wywołuje te funkcje wywołania zwrotnego na poziomie IRQL = DISPATCH_LEVEL. Określając poziom wykonywania, sterownik może wymusić wywołanie tych funkcji wywołania zwrotnego w środowisku IRQL = PASSIVE_LEVEL. Struktura używa następujących reguł podczas ustawiania środowiska IRQL, w którym wywołuje funkcje wywołania zwrotnego obiektów kolejki i plików:
Jeśli sterownik korzysta z automatycznej synchronizacji, framework wywołuje funkcje wywołania obiektów kolejek i plików na poziomie IRQL = DISPATCH_LEVEL, chyba że sterownik poprosi platformę o wywołanie funkcji na poziomie IRQL = PASSIVE_LEVEL.
Jeśli sterownik nie korzysta z automatycznej synchronizacji i nie określa poziomu wykonania, framework może wywoływać funkcje zwrotne kolejki i obiektu pliku sterownika na poziomie IRQL <= DISPATCH_LEVEL.
Jeśli sterownik udostępnia funkcje wywołania zwrotnego obiektów plików, najprawdopodobniej chcesz, aby framework wywoływał te funkcje wywołania zwrotnego przy IRQL = PASSIVE_LEVEL, ponieważ niektóre dane plików, takie jak nazwa pliku, są poddawane stronicowaniu.
Aby podać poziom wykonywania, sterownik musi określić wartość elementu członkowskiego ExecutionLevel struktury WDF_OBJECT_ATTRIBUTES obiektu. Wartości na poziomie wykonywania, które może określić sterownik, to:
WdfExecutionLevelPassive
Framework wywołuje funkcje callback obiektu na poziomie IRQL = PASSIVE_LEVEL.
WdfExecutionLevelDispatch
Struktura może wywoływać funkcje wywołania zwrotnego obiektu w środowisku IRQL <= DISPATCH_LEVEL. Jeśli sterownik używa automatycznej synchronizacji, framework zawsze wywołuje funkcje wywołania zwrotnego na poziomie IRQL = DISPATCH_LEVEL.
WdfExecutionLevelInheritFromParent
Struktura uzyskuje wartość ExecutionLevel obiektu z obiektu nadrzędnego.
Domyślnym poziomem wykonywania obiektów sterowników jest WdfExecutionLevelDispatch. Domyślnym poziomem wykonywania dla wszystkich innych obiektów jest WdfExecutionLevelInheritFromParent.
Aby uzyskać więcej informacji na temat wartości na poziomie wykonywania, zobacz WDF_EXECUTION_LEVEL.
W poniższej tabeli przedstawiono poziom IRQL, na którym platforma może wywoływać funkcje wywołania zwrotnego sterownika dla obiektów kolejki i obiektów plików.
| Zakres synchronizacji | Poziom egzekucji | IRQL funkcji wywołań zwrotnych kolejek i plików |
|---|---|---|
WdfSynchronizationScopeDevice |
WdfExecutionLevelPassive |
Poziom Pasywny |
WdfSynchronizationScopeDevice |
WdfExecutionLevelDispatch |
Poziom_wysyłki |
WdfSynchronizationScopeQueue |
WdfExecutionLevelPassive |
Poziom Pasywny |
WdfSynchronizationScopeQueue |
WdfExecutionLevelDispatch |
Poziom_wysyłki |
WdfSynchronizationScopeNone |
WdfExecutionLevelPassive |
Poziom Pasywny |
WdfSynchronizationScopeNone |
WdfExecutionLevelDispatch |
<= DISPATCH_LEVEL |
Możesz ustawić poziom wykonywania na WdfExecutionLevelPassive lub WdfExecutionLevelDispatch dla sterowników, urządzeń, plików, kolejek, czasomierza i obiektów ogólnych. W przypadku innych obiektów można ustawić tylko WdfExecutionLevelInheritFromParent.
Określ WdfExecutionLevelPassive , jeśli:
Funkcje wywołania zwrotnego sterownika muszą wywoływać metody frameworku lub procedury modelu sterowników systemu Windows (WDM), które można wywołać tylko na poziomie IRQL = PASSIVE_LEVEL.
Funkcje wywołań zwrotnych sterownika muszą uzyskiwać dostęp do stronicowalnego kodu lub stronicowalnych danych. Na przykład, funkcje wywołania zwrotnego obiektów plików uzyskują zwykle dostęp do danych stronicowalnych.
Zamiast ustawiać WdfExecutionLevelPassive, sterownik może ustawić WdfExecutionLevelDispatch i udostępnić funkcję wywołania zwrotnego, która tworzy work items, jeśli musi obsługiwać niektóre operacje na poziomie IRQL = PASSIVE_LEVEL.
Przed podjęciem decyzji, czy sterownik powinien ustawić poziom wykonywania obiektu na WdfExecutionLevelPassive, określ środowisko IRQL, w którym sterownik i inne sterowniki w stosie sterowników są wywoływane. Rozważ następujące sytuacje:
Jeśli sterownik znajduje się na szczycie stosu sterowników trybu jądra, system zwykle wywołuje sterownik na poziomie IRQL = PASSIVE_LEVEL. Klientem takiego sterownika może być sterownik oparty na usłudze UMDF lub aplikacja w trybie użytkownika. Określenie elementu WdfExecutionLevelPassive nie wpływa niekorzystnie na wydajność sterownika, ponieważ struktura nie musi kolejkować wywołań sterownika do elementów roboczych wywoływanych w środowisku IRQL = PASSIVE_LEVEL.
Jeśli sterownik nie znajduje się w górnej części stosu, system prawdopodobnie nie wywołuje sterownika na IRQL = PASSIVE_LEVEL. W związku z tym struktura musi kolejkować wywołania sterownika do elementów do wykonania, które są następnie wykonywane w IRQL = PASSIVE_LEVEL. Ten proces może spowodować niską wydajność sterownika w porównaniu z zezwoleniem na wywoływanie funkcji wywołania zwrotnego sterownika w środowisku IRQL <= DISPATCH_LEVEL.
W przypadku obiektów DPC i obiektów czasomierza, które nie reprezentują czasomierzy na poziomie pasywnym, nie można ustawić członka AutomaticSerialization struktury konfiguracji na TRUE, jeśli ustawisz poziom wykonywania urządzenia nadrzędnego na WdfExecutionLevelPassive. Struktura uzyskuje blokady synchronizacji wywołania zwrotnego obiektu urządzenia w środowisku IRQL = PASSIVE_LEVEL. W związku z tym nie może używać blokad do synchronizowania funkcji wywołania zwrotnego obiektu DPC lub timera, które muszą być wykonywane na poziomie IRQL = DISPATCH_LEVEL. W takim przypadku sterownik powinien używać blokad spinowych frameworku w dowolnym urządzeniu, funkcji DPC lub wywołania zwrotnego obiektu czasomierza, które muszą być wzajemnie zsynchronizowane.
Należy również pamiętać, że w przypadku obiektów czasomierza reprezentujących czasomierze na poziomie pasywnym można ustawić element członkowski AutomatyczneSerializacja struktury konfiguracji na wartość TRUE tylko wtedy, gdy poziom wykonywania urządzenia nadrzędnego jest ustawiony na WdfExecutionLevelPassive.