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.
Podczas wejścia, procedura IoCompletion otrzymuje wskaźnik Context. Gdy procedura wysyłania wywołuje metodę IoSetCompletionRoutine, może podać wskaźnik Kontekstu. Ten wskaźnik może odnosić się do kontekstu ustalonego przez sterownik, którego procedura IoCompletion potrzebuje do przetworzenia IRP. Obszar kontekstu nie może być stronicowalny, ponieważ rutynę IoCompletion można wywołać na poziomie IRQL = DISPATCH_LEVEL.
Rozważ następujące wytyczne dotyczące implementacji procedur IoCompletion:
Rutyna IoCompletion może sprawdzić blok stanu we/wy IRP, aby określić wynik operacji we/wy.
Jeśli procedurę wysyłania przydzielono wejściowy IRP przy użyciu IoAllocateIrp lub IoBuildAsynchronousFsdRequest, procedura IoCompletion musi wywołać IoFreeIrp, aby zwolnić ten IRP, najlepiej przed ukończeniem oryginalnego IRP.
Procedura IoCompletion musi zwolnić wszystkie zasoby przypisane do każdego IRP przez procedurę wysyłającą dla IRP przydzielenego przez sterownik, najlepiej przed zwolnieniem odpowiedniego IRP.
Na przykład, jeśli rutynowa wysyłka przydziela MDL za pomocą IoAllocateMdl i wywołuje IoBuildPartialMdl dla IRP częściowego transferu, procedura IoCompletion musi zwolnić MDL za pomocą IoFreeMdl. Jeśli przydziela zasoby w celu zachowania stanu oryginalnego IRP, musi zwolnić te zasoby, najlepiej przed wywołaniem IoCompleteRequest z oryginalnym IRP i zdecydowanie przed zwróceniem kontroli.
Ogólnie rzecz biorąc, przed zwolnieniem lub ukończeniem IRP, procedura IoCompletion powinna zwolnić wszystkie zasoby przypisane do IRP przez funkcję wysyłania. W przeciwnym razie sterownik musi utrzymywać informacje o zasobach do zwolnienia, zanim procedura IoCompletion zwróci kontrolę po ukończeniu oryginalnego żądania.
Jeśli procedura IoCompletion nie może ukończyć oryginalnego IRP z STATUS_SUCCESS, musi ustawić blok stanu I/O w oryginalnym IRP na wartość zwróconą w przydzielonym przez sterownik IRP, który spowodował, że procedura IoCompletion zakończyła oryginalne żądanie niepowodzeniem.
Jeśli procedura IoCompletion ukończy oryginalne żądanie ze statusem STATUS_PENDING, musi wywołać IoMarkIrpPending z oryginalnym IRP, zanim wywoła IoCompleteRequest.
Jeśli procedury IoCompletion muszą zakończyć się niepowodzeniem oryginalnego protokołu IRP z błędem STATUS_XXX, może zarejestrować błąd. Jednak jest to odpowiedzialność podstawowego sterownika urządzenia za rejestrowanie wszelkich występujących błędów we/wy urządzenia, więc procedury IoCompletion zwykle nie rejestrują błędów.
Gdy procedura IoCompletion przetwarza i zwalnia IRP przydzielony przez sterownik, musi zwrócić kontrolę z STATUS_MORE_PROCESSING_REQUIRED.
Zwracanie STATUS_MORE_PROCESSING_REQUIRED z procedury IoCompletion zapobiega przetwarzaniu ukończenia przez menedżera we/wy dla IRP przydzielonego przez sterownik i zwolnionego. Drugie wywołanie funkcji IoCompleteRequest powoduje, że menedżer we/wy wznowienie wywoływania procedur ukończenia protokołu IRP, począwszy od procedury uzupełniania bezpośrednio powyżej procedury, która zwróciła STATUS_MORE_PROCESSING_REQUIRED.
Jeśli procedura IoCompletion ponownie wykorzystuje przychodzące IRP do wysłania jednego lub większej liczby żądań do niższych sterowników, lub jeśli procedura ponownie próbuje nieudane operacje, powinna zaktualizować kontekst, który procedura IoCompletion utrzymuje dla każdego ponownego wykorzystania lub ponowienia próby IRP. Następnie można ponownie skonfigurować miejsce w stosie we/wy sterownika niższego poziomu, wywołać funkcję IoSetCompletionRoutine z własnym punktem wejścia i wywołać funkcję IoCallDriver dla IRP.
Rutyna IoCompletion nie powinna wywoływać metody IoMarkIrpPending przy każdym ponownym użyciu lub ponawianiu próby protokołu IRP.
Rutyna wysyłki oznaczyła już oryginalny IRP jako oczekujący. Dopóki wszystkie sterowniki w łańcuchu nie zakończą oryginalnego IRP za pomocą funkcji IoCompleteRequest, pozostaje nieukończone.
Przed ponowieniem próby wykonania żądania rutyna IoCompletion powinna zresetować blok stanu we/wy z ustawionym STATUS_SUCCESS dla Status i zerem dla Information, prawdopodobnie po zapisaniu informacji o błędzie, które zostały zwrócone.
Dla każdego ponawiania procedury IoCompletion zwykle dekrementuje liczbę ponownych prób skonfigurowanych przez procedurę wysyłania. Zazwyczaj rutynowa IoCompletion musi wywołać metodę IoCompleteRequest , aby zakończyć się niepowodzeniem iRP, gdy wystąpiła ograniczona liczba ponownych prób.
Procedura IoCompletion musi zwrócić STATUS_MORE_PROCESSING_REQUIRED po wywołaniu metod IoSetCompletionRoutine i IoCallDriver z IRP, który jest ponownie używany lub ponawiany.
Zwracanie STATUS_MORE_PROCESSING_REQUIRED z procedury IoCompletion umożliwia ukończenie przetwarzania ponownego użycia lub ponownego wykonania protokołu IRP przez menedżera we/wy.
Jeśli rutyna IoCompletion nie może ukończyć oryginalnego IRP z STATUS_SUCCESS, musi pozostawić blok stanu We/Wy zwrócony przez niższe sterowniki do ponownego użycia lub powtórzenia operacji, co powoduje, że rutyna IoCompletion nie powiedzie się.
Jeśli procedury IoCompletion zakończą oryginalne żądanie za pomocą STATUS_PENDING, należy wywołać metodę IoMarkIrpPending z oryginalnym IRP, zanim wywoła funkcję IoCompleteRequest.
Jeśli procedury IoCompletion muszą zakończyć się niepowodzeniem oryginalnego protokołu IRP z błędem STATUS_XXX, może zarejestrować błąd. Jednak jest to odpowiedzialność podstawowego sterownika urządzenia za rejestrowanie wszelkich występujących błędów we/wy urządzenia, więc procedury IoCompletion zwykle nie rejestrują błędów.
Każdy sterownik, który ustawia procedurę IoCompletion w IRP, a następnie przekazuje protokół IRP w dół do niższego sterownika, powinien sprawdzić flagę IRP-PendingReturned> w procedurze IoCompletion. Jeśli flaga jest ustawiona, rutynowa IoCompletion musi wywołać metodę IoMarkIrpPending z IRP. Jednak sterownik, który przekazuje IRP, a następnie czeka na zdarzenie, nie powinien oznaczać IRP jako oczekujący. Zamiast tego jego procedura IoCompletion powinna sygnalizować zdarzenie i zwrócić STATUS_MORE_PROCESSING_REQUIRED.
Procedury IoCompletion muszą zwolnić wszystkie zasoby procedury wysyłania przydzielone do przetwarzania oryginalnego IRP, najlepiej przed procedurą IoCompletion wywołuje IoCompleteRequest z oryginalnym IRP i zdecydowanie przed procedurą IoCompletion zwraca kontrolę przed ukończeniem oryginalnego IRP.
Jeśli jakikolwiek sterownik wyższego poziomu ustawił procedurę IoCompletion w oryginalnym IRP, procedura IoCompletion kierowcy nie jest wywoływana, dopóki nie wywołano procedur IoCompletion wszystkich sterowników niższego poziomu.
Dostarczanie zwiększenia priorytetu w wywołaniach do IoCompleteRequest
Jeśli sterownik urządzenia najniższego poziomu może ukończyć protokół IRP w procedurze wysyłania, wywołuje element IoCompleteRequest z wartością PriorityBoost IO_NO_INCREMENT. Nie trzeba zwiększać priorytetu czasu działania, ponieważ sterownik może założyć, że oryginalny żądający nie czekał na ukończenie operacji wejścia/wyjścia.
W przeciwnym razie sterownik najniższego poziomu dostarcza wartość specyficzną dla systemu i typu urządzenia, która zwiększa priorytet czasu wykonywania obiektu żądającego, aby zrekompensować czas oczekiwania żądającego na żądanie we/wy urządzenia. Zobacz Wdm.h lub Ntddk.h, aby uzyskać wartości wzmocnienia.
Sterowniki wyższego poziomu stosują ten sam PriorityBoost co ich odpowiednie podstawowe sterowniki urządzeń, gdy wywołują IoCompleteRequest.
Efekt wywołania IoCompleteRequest
Gdy sterownik wywołuje funkcję IoCompleteRequest, menedżer we/wy wypełnia lokalizację stosu we/wy tego sterownika z zerami przed wywołaniem następnego sterownika wyższego poziomu, jeśli istnieje, który skonfigurował procedurę IoCompletion , która ma być wywoływana dla protokołu IRP.
Procedura IoCompletion sterownika wyższego poziomu może sprawdzać tylko blok stanu we/wy protokołu IRP, aby określić, jak wszystkie niższe sterowniki obsłużyły żądanie.
Wywołujący IoCompleteRequest nie może próbować uzyskać dostępu do dopiero co ukończonego IRP. Taka próba jest błędem programowania, który powoduje awarię systemu.