Freigeben über


Einführung in Kernel Dispatcher-Objekte

Der Kernel definiert eine Reihe von Objekttypen, die als Kernel dispatcher-Objekte bezeichnet werden, oder nur Dispatcher-Objekte. Dispatcher-Objekte umfassen Timerobjekte, Ereignisobjekte, Semaphorobjekte, Mutex-Objekte und Threadobjekte.

Treiber können Dispatcher-Objekte als Synchronisationsmechanismen innerhalb eines nicht willkürlichen Thread-Kontextes verwenden, während sie mit IRQL gleich PASSIVE_LEVEL ausgeführt werden.

Dispatcher Objektzustände

Jeder kerneldefinierte Verteilerobjekttyp verfügt über einen Zustand, der entweder auf "Signaled" festgelegt oder auf "Not-Signaled" festgelegt ist.

Eine Gruppe von Threads kann ihre Vorgänge synchronisieren, wenn ein oder mehrere Threads KeWaitForSingleObject, KeWaitForMutexObject oder KeWaitForMultipleObjects aufrufen. Diese Funktionen verwenden Dispatcher-Objektzeiger als Eingabe und warten, bis eine andere Routine oder thread ein oder mehrere Dispatcherobjekte auf den Signaled-Zustand festlegt.

Wenn ein Thread das KeWaitForSingleObject aufruft, um auf ein Dispatcherobjekt (oder KeWaitForMutexObject für einen Mutex ) zu warten, wird der Thread in einen Wartezustand versetzt, bis das Dispatcherobjekt auf den Signaled-Zustand festgelegt ist. Ein Thread kann KeWaitForMultipleObjects aufrufen, um entweder auf eines oder alle einer Gruppe von Dispatcher-Objekten zu warten, die auf Signalisiert gesetzt werden sollen.

Jedes Mal, wenn ein Dispatcherobjekt auf den Signaled-Zustand festgelegt ist, ändert der Kernel den Zustand eines Threads, der darauf wartet, dass das Objekt bereit ist. (Synchronisierungszeitgeber und Synchronisierungsereignisse sind Ausnahmen von dieser Regel. Wenn ein Synchronisierungsereignis oder ein Timer signalisiert wird, wird nur ein wartender Thread auf den bereiten Zustand festgelegt. Weitere Informationen finden Sie unter Timer-Objekte und DPCs und Ereignisobjekte.) Ein Thread im bereiten Zustand wird entsprechend der aktuellen Laufzeitthreadpriorität und der aktuellen Verfügbarkeit von Prozessoren für jeden Thread mit dieser Priorität ausgeführt.

Wann können Treiber auf Dispatcher-Objekte warten?

Im Allgemeinen können Treiber nur warten, bis Dispatcher-Objekte festgelegt werden, wenn mindestens eine der folgenden Bedingungen erfüllt ist:

  • Der Treiber wird in einem nichtarbiträren Threadkontext ausgeführt.

    Das heißt, Sie können den Thread identifizieren, der in einen Wartezustand wechselt. In der Praxis sind die einzigen Treiberroutinen, die in einem nichtbiträren Threadkontext ausgeführt werden, die DriverEntry-, AddDevice-, Reinitialize- und Unload-Routinen aller Treiber sowie die Verteilerroutinen von Treibern auf höchster Ebene. Alle diese Routinen werden direkt vom System aufgerufen.

  • Der Treiber führt eine vollständig synchrone E/A-Anforderung aus.

    Das heißt, kein Treiber stellt Operationen in die Warteschlange, während er die E/A-Anforderung bearbeitet, und kein Treiber kehrt zurück, bevor der Treiber unter ihm die Bearbeitung der Anforderung abgeschlossen hat.

Außerdem kann ein Treiber nicht in einen Wartezustand eintreten, wenn er bei oder über IRQL gleich DISPATCH_LEVEL ausgeführt wird.

Basierend auf diesen Einschränkungen müssen Sie die folgenden Regeln verwenden:

  • Die Routinen "DriverEntry", "AddDevice", " Reinitialize" und " Unload " eines beliebigen Treibers können auf Verteilerobjekte warten.

  • Die Dispatch-Routinen eines Treibers der höchsten Ebene können auf Dispatcher-Objekte warten.

  • Die Dispatch-Routinen untergeordneter Treiber können auf Dispatch-Objekte warten, wenn die E/A-Operation synchron ist, wie z. B. Create-, Flush-, Shutdown- und Close-Operationen, einige Geräte-E/A-Steuerungsoperationen und einige PnP- und Power-Operationen.

  • Die Aufrufroutinen von Treibern auf niedrigerer Ebene können nicht auf ein Dispatcher-Objekt warten, um asynchrone E/A-Vorgänge abzuschließen.

  • Eine Treiberroutine, die bei IRQL DISPATCH_LEVEL oder höher ausgeführt wird, darf nicht darauf warten, dass ein Dispatcherobjekt in den signalisierten Zustand versetzt wird.

  • Ein Treiber darf nicht versuchen, darauf zu warten, dass ein Dispatcher-Objekt in den Zustand Signalisiert gesetzt wird, um einen Übertragungsvorgang zu oder von einem Paging-Gerät abzuschließen.

  • Treiber-Dispatchroutinen, die Lese-/Schreibanforderungn bedienen, können in der Regel nicht darauf warten, dass ein Dispatcher-Objekt in den Zustand Signaled versetzt wird.

  • Eine Dispatcher-Routine für eine E/A-Steuerungsanforderung eines Geräts kann nur dann darauf warten, dass ein Dispatcher-Objekt in den Zustand Signalisiert gesetzt wird, wenn der Übertragungstyp für den E/A-Steuerungscode METHOD_BUFFERED ist.

  • SCSI-Miniporttreiber sollten keine Kernel-Dispatcherobjekte verwenden. SCSI-Miniporttreiber sollten nur SCSI-Porttreiberunterstützungsroutinen aufrufen.

Jede weitere Standard-Treiberroutine wird in einem beliebigen Thread-Kontext ausgeführt: im Kontext des aktuellen Threads, wenn die Treiberroutine aufgerufen wird, um einen Vorgang in der Warteschlange zu bearbeiten oder einen Geräteinterrupt zu verarbeiten. Darüber hinaus werden die meisten Standardtreiberroutinen bei einer erhöhten IRQL entweder bei DISPATCH_LEVEL oder für Gerätetreiber bei DIRQL ausgeführt.

Bei Bedarf kann ein Treiber einen gerätededizierten Thread erstellen, der auf die anderen Routinen des Treibers (mit Ausnahme einer ISR- oder SynchCritSection-Routine ) warten kann, um ein Dispatcherobjekt auf den Zustand "Signaled" festzulegen und auf den Not-Signaled Zustand zurückzusetzen.

Wenn Sie davon ausgehen, dass Ihr neuer Gerätetreiber häufig länger als 50 Mikrosekunden warten muss, während er während der E/A-Vorgänge auf Änderungen des Gerätezustands wartet, erwägen Sie die Implementierung eines Treibers mit einem gerätededizierten Thread. Wenn der Gerätetreiber auch ein Treiber der höchsten Ebene ist, erwägen Sie die Verwendung von Systemarbeitsthreads und die Implementierung einer oder mehrerer Workerthread-Rückrufroutinen. Siehe PsCreateSystemThread und Verwalten von interlockierten Warteschlangen mit einem Driver-Created Thread.