Punkte, die beim Abbrechen von IRPs zu berücksichtigen sind

In diesem Abschnitt werden Richtlinien für die Implementierung einer Cancel-Routine und die Behandlung abbruchfähiger IRPs erläutert. Weitere Informationen zum Behandeln abbrechbarer IRPs finden Sie unter Ablauf der Steuerung für Cancel-Safe IRP Queuing.

Allgemeine Richtlinien für alle Abbruchroutinen

Der E/A-Manager hält die Abbruchsperre bei jedem Aufruf der Cancel-Routine eines Fahrers bereit. Folglich muss jede Cancel-Routine :

  • Rufen Sie IoReleaseCancelSpinLock auf, bevor die Steuerung zurückgegeben wird.

  • Rufen Sie IoAcquireCancelSpinLock nicht auf, es sei denn, ioReleaseCancelSpinLock wird zuerst aufgerufen.

  • Führen Sie einen wechselseitigen Aufruf von IoReleaseCancelSpinLock für jeden Aufruf an IoAcquireCancelSpinLock durch.

Jedes Mal, wenn die Cancel-RoutineIoReleaseCancelSpinLock aufruft, muss sie die IRQL übergeben, die vom letzten Aufruf von IoAcquireCancelSpinLock zurückgegeben wurde. Wenn die vom E/A-Manager erworbene Drehsperre freigegeben wird (und beim Aufrufen der Cancel-Routine gehalten wurde), muss die Cancel-Routine Irp-CancelIrql> übergeben.

Ein Treiber darf keine externen Routinen (z. B . IoCompleteRequest) aufrufen, während er eine Drehsperre hält, da ein Deadlock auftreten kann.

Verwenden der vom E/A-Manager definierten Warteschlange

Es sei denn, ein Treiber verwaltet seine eigenen internen Warteschlangen von IRPs, seine Cancel-Routine wird mit einem eingehenden IRP aufgerufen, bei dem es sich um eine der folgenden Optionen handeln kann:

  • CurrentIrp im Eingabezielgerätobjekt

  • Ein Eintrag in der Gerätewarteschlange, die dem Zielgerätobjekt zugeordnet ist

Sofern ein Treiber seine eigenen internen Warteschlangen von IRPs nicht verwaltet, sollte seine 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 sie nicht davon ausgehen kann, dass sich der angegebene IRP an einer bestimmten Position in der Gerätewarteschlange befindet.

Aktueller Status der Eingabe-IRP

Wenn eine Cancel-Routine mit einem IRP aufgerufen wird, für den der Treiber bereits mit der E/A-Verarbeitung begonnen hat, und die Anforderung in Kürze abgeschlossen wird, sollte die Cancel-Routine die Systemrücklaufsperre und die Rückgabesteuerung freigeben.

Wenn der aktuelle Status des Eingabe-IRP ausstehend lautet, muss eine Cancel-Routine die folgenden Aktionen ausführen:

  1. Legen Sie den E/A-status block des Eingabe-IRP mit STATUS_CANCELLED für Status und null für Informationen fest.

  2. Lassen Sie alle Spinsperren los, die es hält, einschließlich der Systembruch-Spin-Sperre.

  3. Rufen Sie IoCompleteRequest mit dem angegebenen IRP auf.

Speichern von IRPs in einem abbruchfähigen Zustand

Jede Treiberroutine, die ein IRP in einem abbruchfähigen 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 Supportroutinen wie IoStartPacket, IoAllocateController oder exInterlockedInsert. aufrufen. Listenroutine .

Jede Treiberroutine, die anschließend abbrechbare IRPs verarbeitet, muss überprüfen, ob ein IRP bereits abgebrochen wurde, bevor er mit Vorgängen zur Erfüllung der Anforderung beginnt. Die Routine muss IoSetCancelRoutine aufrufen, um ihren Einstiegspunkt für die Cancel-Routine im IRP auf NULL zurückzusetzen. Erst dann kann diese Routine mit der E/A-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 ebenfalls IRPs zur weiteren Verarbeitung durch andere Treiberroutinen übergibt und diese IRPs möglicherweise in einem abbruchfähigen Zustand gehalten werden.

Jeder Treiber auf höherer Ebene, der ein IRP in einem abbruchfähigen Zustand enthält, muss seinen Cancel-Einstiegspunkt auf NULL zurücksetzen, bevor er den IRP mit IoCallDriver an den nächstniedrigen Treiber übergibt.

Abbrechen einer IRP

Jeder Treiber auf höherer Ebene kann IoCancelIrp mit einem IRP aufrufen, das er zugewiesen und zur weiteren Verarbeitung durch Treiber auf niedrigerer Ebene übergeben hat. Ein solcher Treiber kann jedoch nicht davon ausgehen, dass der angegebene IRP mit STATUS_CANCELLED von niedrigeren Treibern abgeschlossen wird.

Synchronization

Ein Treiber kann (oder muss je nach Design) zusätzliche Zustandsinformationen in seiner Geräteerweiterung verwalten, um die abbruchfähige status von IRPs nachzuverfolgen. Wenn dieser Zustand von Treiberroutinen freigegeben wird, die unter IRQL <= DISPATCH_LEVEL ausgeführt werden, sollten die freigegebenen Daten mit einer vom Treiber zugewiesenen und initialisierten Spinsperre geschützt werden.

Der Treiber sollte seine Käufe und Freigaben der System-Abbruch-Spin-Sperre und seine eigenen Spinsperren sorgfältig verwalten. Es sollte die Systemabbruch-Spin-Sperre für die kürzesten möglichen Intervalle halten. Vor dem Zugriff auf eine abbruchfähige IRP sollte ein solcher Treiber immer den Rückgabewert von IoSetCancelRoutine überprüfen, um zu bestimmen, ob die Cancel-Routine bereits ausgeführt wird (oder kurz vor der Ausführung steht). Wenn ja, sollte die Cancel-Routine die IRP abschließen.

Wenn ein Gerätetreiber Zustandsinformationen zu abbruchfähigen IRPs verwaltet, die von verschiedenen Treiberroutinen mit seiner ISR geteilt werden, müssen diese anderen Routinen den Zugriff auf den freigegebenen Zustand mit der ISR synchronisieren. Nur eine vom Treiber bereitgestellte SynchCritSection-Routine kann auf Zustandsinformationen zugreifen, die für die ISR auf multiprozessorsichere Weise freigegeben werden.

Weitere Informationen finden Sie unter Synchronisierungstechniken.