Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
In diesem Abschnitt werden Richtlinien für die Implementierung einer Cancel-Routine und das Behandeln von abbruchfähigen IRPs erläutert. Weitere Informationen zum Behandeln von abbrechbaren IRPs finden Sie im Fluss der Steuerung für Cancel-Safe IRP Queuing.
Allgemeine Richtlinien für alle Abbruchroutinen
Der E/A-Manager hält den Abbruch-Spinlock jedes Mal, wenn er die Cancel-Routine eines Treibers aufruft. Folglich muss jede Cancel-Routine :
Rufen Sie IoReleaseCancelSpinLock auf, bevor sie das Steuerelement zurückgibt.
Rufen Sie IoAcquireCancelSpinLock nicht auf, es sei denn, dass Sie zuerst IoReleaseCancelSpinLock aufrufen.
Rufen Sie für jeden Anruf, den es an IoAcquireCancelSpinLock tätigt, eine entsprechende Ausführung von IoReleaseCancelSpinLock auf.
Jedes Mal, wenn die Cancel-RoutineIoReleaseCancelSpinLock aufruft, muss sie die IRQL übergeben, die vom letzten Aufruf an IoAcquireCancelSpinLock zurückgegeben wird. Beim Freigeben der Spin-Sperre, die der E/A-Manager erworben hat (und gehalten, als die Cancel-Routine aufgerufen wurde), muss die Cancel-RoutineIrp->CancelIrql übergeben.
Ein Treiber darf keine externen Routinen (z. B. IoCompleteRequest) aufrufen, während ein Spinlock gehalten wird, da dies zu einem Deadlock führen kann.
Verwenden der vom E/A-Manager definierten Warteschlange
Wenn ein Treiber keine eigenen internen IRP-Warteschlangen verwaltet, wird die Cancel-Routine mit einem eingehenden IRP aufgerufen, die eine der folgenden sein kann:
CurrentIrp im Eingabezielgerätobjekt
Ein Eintrag in der Gerätewarteschlange, die dem Zielgerätobjekt zugeordnet ist
Wenn ein Treiber keine eigenen internen Warteschlangen von IRPs verwaltet, sollte die Cancel-RoutineKeRemoveEntryDeviceQueue mit dem Eingabe-IRP aufrufen, um zu testen, ob es sich um einen Eintrag in der Gerätewarteschlange handelt, die dem Zielgerätobjekt zugeordnet ist. Die Cancel-Routine des Treibers kann KeRemoveDeviceQueue oder KeRemoveByKeyDeviceQueuenicht aufrufen, da nicht davon ausgegangen werden kann, dass sich der angegebene IRP an einer bestimmten Position in der Gerätewarteschlange befindet.
Aktueller Status des Eingabe-IRP
Wenn eine Cancel-Routine mit einem IRP aufgerufen wird, für das der Treiber bereits die E/A-Verarbeitung gestartet hat und die Anforderung in Kürze abgeschlossen wird, sollte die Cancel-Routine den System-Spinlock freigeben und die Kontrolle zurückgeben.
Wenn der aktuelle Status der Eingabe-IRP "Pending" ist, muss eine Cancel-Routine Folgendes ausführen:
Setzen Sie den E/A-Statusblock des Eingabe-IRP mit STATUS_CANCELLED für Status und mit Null für Informationen fest.
Lassen Sie alle Drehsperren los, die sie halten, einschließlich der Drehungssperre des Systems.
Rufen Sie IoCompleteRequest mit dem angegebenen IRP auf.
Halten von IRPs in einem stornierbaren Zustand
Jede Treiberroutine, die einen IRP in einem abbrechbaren Zustand enthält, muss IoMarkIrpPending aufrufen und IoSetCancelRoutine aufrufen, um den Einstiegspunkt für die Cancel-Routine im IRP festzulegen. Nur dann kann diese Treiberroutine zusätzliche Unterstützungsroutinen wie IoStartPacket, IoAllocateController oder eine ExInterlockedInsert..List-Routine aufrufen.
Jede Treiberroutine, die anschließend abbruchfähige IRPs verarbeitet, muss überprüfen, ob ein IRP bereits abgebrochen wurde, bevor er Vorgänge startet, um die Anforderung zu erfüllen. Die Routine muss IoSetCancelRoutine aufrufen, um den Einstiegspunkt für die Cancel-Routine im IRP auf NULL zurückzusetzen. Nur dann kann diese Routine mit der I/O-Verarbeitung für die Eingabe-IRP beginnen.
Eine Routine muss möglicherweise den Einstiegspunkt für eine Cancel-Routine in einem IRP zurücksetzen, wenn sie auch IRPs zur weiteren Verarbeitung durch andere Treiberroutinen übergibt und diese IRPs möglicherweise in einem abbruchfähigen Zustand gespeichert werden.
Jeder Treiber auf höherer Ebene, der einen IRP in einem abbrechbaren Zustand enthält, muss seinen Cancel-Einstiegspunkt auf NULL zurücksetzen, bevor er das IRP an den nächsten niedrigeren Treiber mit IoCallDriver weitergibt.
Abbrechen eines IRP
Jeder Treiber auf höherer Ebene kann IoCancelIrp mit einem IRP aufrufen, das er zugewiesen und für die weitere Verarbeitung durch Niedrigere Treiber übergeben hat. Ein solcher Treiber kann jedoch nicht damit rechnen, dass das angegebene IRP von niedrigeren Treibern mit STATUS_CANCELLED abgeschlossen wird.
Synchronisierung
Ein Treiber kann (oder muss je nach Design) zusätzliche Zustandsinformationen in der Geräteerweiterung verwalten, um den abbruchfähigen Status von IRPs nachzuverfolgen. Wenn dieser Zustand von Treiberroutinen gemeinsam verwendet wird, die bei IRQL <= DISPATCH_LEVEL ausgeführt werden, sollten die freigegebenen Daten durch eine vom Treiber zugewiesene und initialisierte Spinlock geschützt werden.
Der Treiber sollte seine Erwerbungen und Freigaben des Systemabbruch-Spinlocks und seiner eigenen Spinlocks sorgfältig verwalten. Es sollte die Drehungssperre des Systems für die kürzesten möglichen Intervalle halten. Vor dem Zugriff auf ein abbrechbares IRP sollte ein solcher Treiber immer den Rückgabewert von IoSetCancelRoutine überprüfen, um festzustellen, ob die Cancel-Routine bereits ausgeführt wird (oder gerade ausgeführt wird); wenn ja, sollte die Cancel-Routine das IRP abschließen lassen.
Wenn ein Gerätetreiber Zustandsinformationen zu abbruchbaren IRPs verwaltet, die verschiedene Treiberroutinen mit ihrem ISR teilen, müssen diese anderen Routinen den Zugriff auf den gemeinsam genutzten Zustand mit dem ISR synchronisieren. Nur eine vom Treiber bereitgestellte SynchCritSection-Routine kann auf Zustandsinformationen zugreifen, die in einer multiprozessor-sicheren Weise mit dem ISR geteilt werden.
Weitere Informationen finden Sie unter "Synchronisierungstechniken".