Einrichten und Verwenden von Gerätewarteschlangen
Ein Treiber richtet ein Gerätewarteschlangenobjekt durch Aufrufen von KeInitializeDeviceQueue bei der Treiber- oder Geräteinitialisierung ein. Nach dem Starten seiner Geräte fügt der Treiber IRPs in diese Warteschlange ein, indem er KeInsertDeviceQueue oder KeInsertByKeyDeviceQueue aufruft. Die folgende Abbildung veranschaulicht diese Aufrufe.
Wie in dieser Abbildung gezeigt, muss der Treiber den Speicher für ein Gerätewarteschlangenobjekt bereitstellen, das resident sein muss. Treiber, die ein Gerätewarteschlangenobjekt einrichten, stellen in der Regel den erforderlichen Speicher in der Geräteerweiterung eines vom Treiber erstellten Geräteobjekts bereit, aber der Speicher kann sich in einer Controllererweiterung befinden, wenn der Treiber ein Controllerobjekt oder einen nicht ausgelagerten Pool verwendet, der vom Treiber zugeordnet wird.
Wenn der Treiber Speicher für das Gerätewarteschlangenobjekt in einer Geräteerweiterung bereitstellt, ruft er nach dem Erstellen des Geräteobjekts und vor dem Starten des Geräts KeInitializeDeviceQueue auf. Anders ausgedrückt: Der Treiber kann die Warteschlange über seine AddDevice-Routine initialisieren oder wenn er eine PnP-IRP_MN_START_DEVICE-Anforderung verarbeitet. Beim Aufruf von KeInitializeDeviceQueue übergibt der Treiber einen Zeiger auf den Speicher, den er für das Gerätewarteschlangenobjekt bereitstellt.
Nach dem Starten seiner Geräte kann der Treiber ein IRP in seine Gerätewarteschlange einfügen, indem er KeInsertDeviceQueue aufruft, der den IRP am Ende der Warteschlange platziert, oder KeInsertByKeyDeviceQueue, der den IRP gemäß einem vom Treiber festgelegten SortKey-Wert in die Warteschlange platziert, wie in der vorherigen Abbildung dargestellt.
Jede dieser Supportroutinen gibt einen booleschen Wert zurück, der angibt, ob der IRP in die Warteschlange eingefügt wurde. Jeder dieser Aufrufe legt auch den Status des Gerätewarteschlangenobjekts auf Beschäftigt fest, wenn die Warteschlange derzeit leer ist (Nicht gebucht). Wenn die Warteschlange jedoch leer ist (Not-Busy), fügt keine KeInsertXxxDeviceQueue-Routine den IRP in die Warteschlange ein. Stattdessen wird der Status des Gerätewarteschlangenobjekts auf Beschäftigt festgelegt und FALSE zurückgegeben. Da die IRP nicht in die Warteschlange eingereiht wurde, muss der Treiber sie zur weiteren Verarbeitung an eine andere Treiberroutine übergeben.
Befolgen Sie beim Einrichten zusätzlicher Gerätewarteschlangen diese Implementierungsrichtlinie:
Wenn ein Aufruf von KeInsertXxxDeviceQueueFALSE zurückgibt, muss der Aufrufer den IRP übergeben, für den er versucht hat, für die weitere Verarbeitung an eine andere Treiberroutine zu warten. Der Aufruf von KeInsertXxxDeviceQueue ändert jedoch den Status des Gerätewarteschlangenobjekts in Beschäftigt, sodass der nächste IRP in die Warteschlange eingefügt wird, es sei denn, der Treiber ruft zuerst KeRemoveXxxDeviceQueue auf.
Wenn der Status des Gerätewarteschlangenobjekts auf Beschäftigt festgelegt ist, kann der Treiber eine IRP zur weiteren Verarbeitung aus der Warteschlange entfernen oder den Zustand auf Not-Busy zurücksetzen, indem eine der folgenden Supportroutinen aufgerufen wird:
KeRemoveDeviceQueue zum Entfernen des IRP am Anfang der Warteschlange
KeRemoveByKeyDeviceQueue zum Entfernen eines IRP, das gemäß einem vom Treiber bestimmten SortKey-Wert ausgewählt wurde
KeRemoveEntryDeviceQueue , um einen bestimmten IRP in der Warteschlange zu entfernen oder zu bestimmen, ob sich ein bestimmter IRP in der Warteschlange befindet
KeRemoveEntryDeviceQueue gibt einen Booleschen Wert zurück, der angibt, ob sich der IRP in der Gerätewarteschlange befand.
Wenn Sie eine dieser Routinen aufrufen, um einen Eintrag aus einer leeren Gerätewarteschlange zu entfernen, wird der Warteschlangenstatus in Nicht gebucht geändert.
Jedes Gerätewarteschlangenobjekt wird durch eine integrierte Spin-Sperre von Führungskräften geschützt (nicht in der Abbildung Verwenden eines Gerätewarteschlangenobjekts ). Daher kann ein Treiber IRPs in die Warteschlange einfügen und sie auf multiprozessorsichere Weise aus jeder Treiberroutine entfernen, die kleiner oder gleich IRQL = DISPATCH_LEVEL ausgeführt wird. Aufgrund dieser IRQL-Einschränkung kann ein Treiber keine KeXxxDeviceQueue-Routine aus seinen ISR- oder SynchCritSection-Routinen aufrufen, die bei DIRQL ausgeführt werden.
Weitere Informationen finden Sie unter Verwalten von Hardwareprioritäten und Spinsperren . Informationen zu IRQL-Anforderungen für eine bestimmte Supportroutine finden Sie auf der Referenzseite der Routine.