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.
W poniższych przykładach pokazano, co minidriver musi zrobić w odniesieniu do synchronizacji i zawiera przykłady, gdy synchronizacja nie powinna być używana:
Przykład pierwszy: Minidriver z działającym ISR
Jeśli synchronizacja klas strumienia jest włączona, wszystkie punkty wejścia minidriver są wywoływane w podniesionym IRQL, przy użyciu KeSynchronizeExecution, co oznacza, że poziom IRQ adaptera i wszystkie niższe poziomy IRQ są maskowane, gdy minidriver wykonuje swój kod. Dlatego konieczne jest, aby minidriver wykonuje tylko niewielką ilość pracy w tym trybie.
Minidriver nie powinien uruchamiać kodu, który zwykle zajmuje więcej niż 10 do 20 mikrosekund w podniesionym środowisku IRQL. Jeśli używasz wersji debugowej stream.sys, klasa strumienia rejestruje ilość czasu spędzonego w podniesionym IRQL i zgłasza, czy sterownik spędza tam zbyt dużo czasu. Jeśli minidriver po prostu musi programować sprzętowe rejestry DMA dla żądania lub po prostu musi odczytywać porty w swoim ISR, zwykle jest dopuszczalne, aby przeprowadzić całe przetwarzanie na podwyższonym IRQL.
Jeśli minidriver musi wykonać przetwarzanie, które zajmuje więcej niż kilka mikrosekund, takie jak minidriver, który przesyła dane za pośrednictwem PIO, minidriver powinien używać StreamClassCallAtNewPriority do zaplanowania zwrotnego wywołania na poziomie DISPATCH_LEVEL. W wywołaniu zwrotnym minidriver może zająć od około 1/2 do 1 milisekundy, aby wykonać swoje przetwarzanie. Jedną z rzeczy, o których należy pamiętać w tym trybie, jest to, że wywołanie zwrotne na poziomie DISPATCH_LEVEL nie jest synchronizowane z ISR.
Ten brak synchronizacji nie jest problemem, jeśli sprzęt pozostaje stabilny, gdy minidriver uzyskuje dostęp do zasobów (na przykład portów lub kolejki) zarówno podczas wywołania zwrotnego, jak i w ISR. Jeśli jednak niestabilność może być problemem, minidriver musi użyć StreamClassCallAtNewPriority, aby zaplanować wywołanie zwrotne o wysokim priorytecie, w którym wywołanie zwrotne na poziomie DISPATCH_LEVEL dotyka zasobów, które są współużytkowane z zasobami używanymi przez ISR.
Należy pamiętać, że wywołanie zwrotne o wysokim priorytecie jest równoważne wywołaniu KeSynchronizeExecution. KeSynchronizeExecution wymaga, aby minidriver odwoływał się do kilku parametrów, które nie są wymagane przez StreamClassCallAtNewPriority, ale ogólnie rzecz biorąc, oba wynikają w tym samym zachowaniu.
Jeśli minidriver musi od czasu do czasu uruchomić kod, który zajmuje więcej niż od 0,5 do 1 milisekundy, lub sporadycznie musi wywołać usługi na poziomie PASSIVE_LEVEL (na przykład podczas inicjalizacji), ustawienie StreamClassCallAtNewPriority na niski priorytet może zostać wykorzystane do uzyskania wątku roboczego działającego na poziomie PASSIVE_LEVEL. Należy pamiętać, że wywołanie zwrotne o niskim priorytecie nie jest synchronizowane z niczym i że minidriver może odbierać nowe żądania (przy założeniu, że parametr ReadyForNextRequest NotificationType jest oczekujący) lub wywołanie ISR podczas uruchamiania wywołania zwrotnego o niskim priorytecie.
Przykład drugi: Minidriver bez ISR
Jeśli synchronizacja klas strumienia jest włączona, punkty wejścia minidrivera są wywoływane w DISPATCH_LEVEL. Minidriver może przetwarzać dane przez od około 1/2 do 1 milisekundy długości bez konieczności dostosowywania priorytetu. Jeśli minidriver tylko czasami musi uruchomić kod, który zajmuje więcej niż ½ milisekundy, lub czasami musi wywoływać usługi na poziomie PASSIVE_LEVEL (na przykład przy inicjalizacji), to StreamClassCallAtNewPriority z niskim priorytetem można użyć do uzyskania wątku roboczego na poziomie PASSIVE_LEVEL. Pamiętaj, że wywołanie zwrotne o niskim priorytecie nie jest synchronizowane z niczym, a minidriver może odbierać nowe żądania (przy założeniu, że parametr ReadyForNextRequest NotificationType jest oczekujący) podczas uruchamiania wywołania zwrotnego o niskim priorytecie.
Gdy synchronizacja klas strumienianie powinna być używana
Poniżej przedstawiono przykłady sytuacji, w których synchronizacja klas strumienia nie powinna być używana. Są to:
Gdy sterowniki często (ponad 20 procent żądań odbieranych przez minidriver) muszą wykonać przetwarzanie, które trwa ponad 1 milisekund lub często wywoływać usługi PASSIVE_LEVEL, takie jak usługi Microsoft DirectDraw. Podczas korzystania z wersji debugowania stream.sys klasa strumienia będzie sprawdzać poprawność obu tych przypadków i zatrzyma działanie, jeśli zostaną one wykryte przy włączonej synchronizacji.
Gdy minidriver jest filtrem bez skojarzonego sprzętu. Taki minidriver powinien działać na poziomie PASSIVE_LEVEL, ponieważ nie ma bazowego sprzętu do synchronizacji, a minidriver zwykle wykonuje wiele przetwarzania. W tym przypadku łatwiej jest przeprowadzić własną synchronizację niż marnować zasoby poprzez synchronizację klas strumieniowych. W razie potrzeby użyj mutexów, aby chronić kolejki.
Błędy w kodzie synchronizacji często mogą być trudne do znalezienia, a w niektórych środowiskach (takich jak systemy operacyjne oparte na NT działające w systemach wieloprocesorowych) błędy mogą pojawić się dopiero po wielu godzinach stresu. Na podstawie doświadczenia z dostawcami, nie są to te kwestie, które większość dostawców ma ani możliwości, ani chęci debugować. Tylko autorzy sterowników zaznajomieni z pisaniem w pełni asynchronicznych sterowników urządzeń WDM powinni próbować wykonać własną synchronizację.
Gdy minidriver jest sterownikiem typu magistrala-na-magistrali (na przykład sterownik peryferyjny USB lub 1394), który nie zajmuje się synchronizacją rzeczywistego sprzętu, ale po prostu przesyła żądania do następnej warstwy na poziomie PASSIVE_LEVEL i odbiera wywołania zwrotne zwykle na poziomie DISPATCH_LEVEL.