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.
Fast der gesamte Code in einem frameworkbasierten Treiber befindet sich in Ereignisrückruffunktionen. Das Framework synchronisiert automatisch die meisten Rückruffunktionen eines Treibers wie folgt:
Das Framework synchronisiert immer allgemeine Geräteobjekt-, Funktionsgeräteobjekt (FDO)- und physisches Geräteobjekt (PDO)-Ereignisrückruffunktionen miteinander. Für jedes Gerät kann jeweils nur eine der Rückruffunktionen aufgerufen werden. Die Ausnahme ist EvtDeviceSurpriseRemoval, EvtDeviceQueryRemove und EvtDeviceQueryStop. Diese Rückruffunktionen unterstützen Plug and Play (PnP) sowie Energieverwaltungsereignisse und werden bei IRQL = PASSIVE_LEVEL aufgerufen.
Optional kann das Framework die Ausführung der Rückruffunktionen synchronisieren, die die E/A-Anforderungen eines Treibers verarbeiten, damit diese Rückruffunktionen jeweils einzeln ausgeführt werden. Insbesondere kann das Framework die Rückruffunktionen für Warteschlangen-, Interrupt-, verzögerte Prozeduraufrufe (DPC)-, Timer-, Arbeitsobjekte- und Dateiobjekte sowie die EvtRequestCancel-Rückruffunktion des Anforderungsobjekts synchronisieren. Das Framework ruft die meisten dieser Rückruffunktionen bei IRQL = DISPATCH_LEVEL auf, aber Sie können erzwingen, dass die Warteschlangen- und Dateiobjektrückruffunktionen bei IRQL = PASSIVE_LEVEL ausgeführt werden. (Rückruffunktionen für Arbeitsaufgaben werden immer bei PASSIVE_LEVEL ausgeführt.)
Das Framework implementiert diese automatische Synchronisierung mithilfe einer Reihe interner Synchronisierungssperren. Das Framework stellt sicher, dass zwei oder mehr Threads nicht gleichzeitig dieselbe Rückruffunktion aufrufen können. Jeder Thread muss warten, bis er eine Synchronisierungssperre erhalten kann, bevor er eine Rückruffunktion aufruft. (Optional können Treiber diese Synchronisierungssperren auch bei Bedarf abrufen. Weitere Informationen finden Sie unter Verwenden von Framework-Sperren.)
Der Treiber sollte objektspezifische Daten im Objektkontextbereich speichern. Wenn Ihr Treiber nur frameworkdefinierte Schnittstellen verwendet, können nur Rückruffunktionen, die ein Handle für das Objekt empfangen, auf diese Daten zugreifen. Wenn das Framework Aufrufe der Rückruffunktionen des Treibers synchronisiert, wird jeweils nur eine Rückruffunktion aufgerufen. Auf den Kontextbereich des Objekts kann jeweils nur von einer Rückruffunktion zugegriffen werden.
Sofern Ihr Treiber die passive Interrupt-Behandlung nicht implementiert, muss der Code, der Interrupts bearbeitet und auf Interrupt-Daten zugreift, bei der IRQL (DIRQL) des Geräts ausgeführt werden und erfordert zusätzliche Synchronisation. Weitere Informationen finden Sie unter "Interruptcode synchronisieren".
Wenn Ihr Treiber die automatische Synchronisierung der Rückruffunktionen aktiviert, die E/A-Anforderungen verarbeiten, synchronisiert das Framework diese Rückruffunktionen so, dass sie jeweils einzeln ausgeführt werden. In der folgenden Tabelle sind die Rückruffunktionen aufgeführt, die vom Framework synchronisiert werden.
| Objekttyp | Synchronisierte Rückruffunktionen |
|---|---|
Queue-Objekt |
Anforderungshandler, EvtIoQueueState, EvtIoResume, EvtIoStop |
File-Objekt |
Alle Rückruffunktionen |
Anforderungsobjekt |
Optional kann das Framework diese Rückruffunktionen auch mit allen Interrupt-, DPC-, Arbeits- und Zeitgeberobjektrückruffunktionen synchronisieren, die ihr Treiber für das Gerät bereitstellt (mit Ausnahme der EvtInterruptIsr-Rückruffunktion des Interruptobjekts). Um diese zusätzliche Synchronisierung zu aktivieren, muss der Treiber das AutomaticSerialization-Element der Konfigurationsstrukturen dieser Objekte auf TRUE festlegen.
Zusammenfassend bietet die automatische Synchronisierungsfunktion des Frameworks die folgenden Features:
Das Framework synchronisiert immer die PnP- und Energieverwaltungsrückruffunktionen jedes Geräts.
Optional kann das Framework die Anforderungshandler einer E/A-Warteschlange und einige zusätzliche Rückruffunktionen synchronisieren (siehe vorherige Tabelle).
Ein Treiber kann das Framework bitten, Rückruffunktionen für Interrupt-, DPC-, Arbeitsaufgaben- und Zeitgeberobjekte zu synchronisieren.
Treiber müssen Code, der Interrupts bearbeitet und auf zugehörige Daten zugreift, synchronisieren, indem sie die in "Synchronisieren von Interruptcode" beschriebenen Techniken anwenden.
Das Framework synchronisiert nicht die anderen Rückruffunktionen eines Treibers, z. B. die CompletionRoutine-Rückruffunktion des Treibers, oder die Rückruffunktionen, die das E/A-Zielobjekt definiert. Stattdessen stellt das Framework zusätzliche Sperren bereit, mit denen Treiber diese Rückruffunktionen synchronisieren können.
Auswählen eines Synchronisierungsbereichs
Sie können festlegen, dass das Framework alle Rückruffunktionen synchronisiert, die allen E/A-Warteschlangen eines Geräts zugeordnet sind. Alternativ können Sie festlegen, dass das Framework die Rückruffunktionen für jede E/A-Warteschlange eines Geräts separat synchronisieren soll. Die für Ihren Treiber verfügbaren Synchronisierungsoptionen lauten wie folgt:
Synchronisierung auf Geräteebene
Das Framework synchronisiert die Rückruffunktionen für alle E/A-Warteschlangen des Geräts, sodass sie jeweils einzeln ausgeführt werden. Das Framework erreicht diese Synchronisierung durch Abrufen der Synchronisierungssperre des Geräts, bevor eine Rückruffunktion aufgerufen wird.
Synchronisierung auf Warteschlangenebene
Das Framework synchronisiert die Rückruffunktionen für jede einzelne E/A-Warteschlange, sodass sie jeweils einzeln ausgeführt werden. Das Framework erreicht diese Synchronisierung, indem es die Synchronisierungssperre der Warteschlange erwirbt, bevor es eine Rückruffunktion aufruft.
Keine Synchronisierung
Das Framework synchronisiert die Ausführung der Rückruffunktionen in der vorherigen Tabelle nicht und ruft vor dem Aufrufen der Rückruffunktionen keine Synchronisierungssperre ab. Wenn die Synchronisierung erforderlich ist, muss der Treiber ihn bereitstellen.
Um anzugeben, ob das Framework Synchronisierung auf Geräteebene, Synchronisierung auf Warteschlangenebene oder keine Synchronisierung für Den Treiber bereitstellen soll, geben Sie einen Synchronisierungsbereich für Ihr Treiberobjekt, Geräteobjekte oder Warteschlangenobjekte an. Das SynchronizationScope-Element der WDF_OBJECT_ATTRIBUTES Struktur eines Objekts identifiziert den Synchronisierungsbereich des Objekts. Die Synchronisierungsbereichswerte, die Ihr Treiber angeben kann, sind:
WdfSynchronizationScopeDevice
Das Framework synchronisiert sich durch Abrufen der Synchronisierungssperre eines Geräteobjekts.
WdfSynchronizationScopeQueue
Das Framework synchronisiert sich, indem es die Synchronisierungssperre eines Warteschlangenobjekts erhält.
WdfSynchronizationScopeNone
Das Framework wird nicht synchronisiert und erhält keine Synchronisierungssperre.
WdfSynchronizationScopeInheritFromParent
Das Framework ruft den SynchronizationScope-Wert eines Objekts vom übergeordneten Objekt ab.
Vermeiden Sie im Allgemeinen die Verwendung der Synchronisierung auf Geräteebene.
Weitere Informationen zu den Synchronisierungsbereichswerten finden Sie unter WDF_SYNCHRONIZATION_SCOPE.
Der Standardsynchronisierungsbereich für Treiberobjekte ist WdfSynchronizationScopeNone. Der Standardsynchronisierungsbereich für Geräte- und Warteschlangenobjekte ist WdfSynchronizationScopeInheritFromParent.
Um das Framework für die Bereitstellung der Gerätesynchronisierung für alle Geräte zu verwenden, legen Sie "SynchronizationScope" in der WDF_OBJECT_ATTRIBUTES Struktur des Treiberobjekts auf WdfSynchronizationScopeDevice fest. Verwenden Sie den standardmäßigen WdfSynchronizationScopeInheritFromParent-Wert für jedes Geräteobjekt .
Verwenden Sie den Standardmäßigen WdfSynchronizationScopeNone-Wert für das Treiberobjekt , um die Synchronisierung auf Geräteebene für einzelne Geräte bereitzustellen. Legen Sie SynchronizationScope auf WdfSynchronizationScopeDevice in der WDF_OBJECT_ATTRIBUTES Struktur einzelner Geräteobjekte fest.
Wenn das Framework die Synchronisierung auf Warteschlangenebene für ein Gerät bereitstellen soll, können Sie die folgenden Techniken verwenden:
Aktivieren Sie für Frameworkversionen 1.9 und höher die Synchronisierung auf Warteschlangenebene für einzelne Warteschlangen, indem Sie WdfSynchronizationScopeQueue in der WDF_OBJECT_ATTRIBUTES Struktur des Warteschlangenobjekts festlegen. Diese Technik wird bevorzugt.
Alternativ können Sie die folgenden Schritte in allen Frameworkversionen ausführen:
- Legen Sie SynchronizationScope in der WDF_OBJECT_ATTRIBUTES Struktur des Geräteobjekts auf WdfSynchronizationScopeQueue fest.
- Verwenden Sie den standardmäßigen Wert von WdfSynchronizationScopeInheritFromParent für die Warteschlangenobjekte jedes Geräts.
Wenn Sie nicht möchten, dass das Framework die Rückruffunktionen synchronisiert, die die E/A-Anforderungen Ihres Treibers verarbeiten, verwenden Sie den Standard-SynchronizationScope-Wert für treiber-, Geräte- und Warteschlangenobjekte. In diesem Fall synchronisiert das Framework nicht automatisch die anfragenbezogenen I/O-Rückruffunktionen des Treibers. Das Framework kann die Rückruffunktionen unter IRQL <= DISPATCH_LEVEL aufrufen.
Durch Festlegen eines SynchronizationScope-Werts werden nur die Rückruffunktionen synchronisiert, die die vorherige Tabelle enthält. Wenn das Framework auch die Interrupt-, DPC-, Arbeits- und Timerobjektrückruffunktionen des Treibers synchronisieren soll, legen Sie das AutomaticSerialization-Element der Konfigurationsstrukturen dieser Objekte auf TRUE fest.
Sie können die AutomaticSerialization jedoch nur dann auf TRUE festlegen, wenn alle Rückruffunktionen, die Sie synchronisieren möchten, mit demselben IRQL ausgeführt werden sollen. Wenn Sie eine Ausführungsebene auswählen, die als Nächstes beschrieben wird, kann dies zu inkompatiblen IRQL-Ebenen führen. In einer solchen Situation muss der Treiber Frameworksperren verwenden, anstatt AutomaticSerialization festzulegen. Weitere Informationen zu den Konfigurationsstrukturen für Interrupt-, DPC-, Arbeitsaufgaben- und Zeitgeberobjekte sowie weitere Informationen zu Einschränkungen, die zum Festlegen der AutomaticSerialisierung in diesen Strukturen gelten, finden Sie unter WDF_INTERRUPT_CONFIG, WDF_DPC_CONFIG, WDF_WORKITEM_CONFIG und WDF_TIMER_CONFIG.
Wenn Sie die AutomatischeSerialisierung auf TRUE festlegen, wählen Sie die Synchronisierung auf Warteschlangenebene aus.
Auswählen einer Ausführungsebene
Wenn ein Treiber einige Typen von Frameworkobjekten erstellt, kann er eine Ausführungsebene für das Objekt angeben. Die Ausführungsebene gibt die IRQL an, bei der das Framework die Ereignisrückruffunktionen des Objekts aufruft, die die E/A-Anforderungen eines Treibers behandeln.
Wenn ein Treiber eine Ausführungsebene bereitstellt, wirkt sich die angegebene Ebene auf die Rückruffunktionen für Warteschlangen- und Dateiobjekte aus. Normalerweise ruft das Framework diese Rückruffunktionen bei IRQL = DISPATCH_LEVEL auf, wenn der Treiber die automatische Synchronisierung verwendet. Durch Angeben einer Ausführungsebene kann der Treiber das Framework erzwingen, diese Rückruffunktionen bei IRQL = PASSIVE_LEVEL aufzurufen. Das Framework verwendet die folgenden Regeln beim Festlegen der IRQL, bei denen es Warteschlangen- und Dateiobjektrückruffunktionen aufruft:
Wenn ein Treiber die automatische Synchronisierung verwendet, ruft das Framework seine Warteschlangen- und Dateiobjektrückruffunktionen bei IRQL = DISPATCH_LEVEL auf, es sei denn, der Treiber fordert das Framework auf, seine Rückruffunktionen bei IRQL = PASSIVE_LEVEL aufzurufen.
Wenn ein Treiber keine automatische Synchronisierung verwendet und keine Ausführungsebene angibt, kann das Framework die Warteschlangen- und Dateiobjektrückruffunktionen des Treibers bei IRQL <= DISPATCH_LEVEL aufrufen.
Wenn Ihr Treiber Dateiobjektrückruffunktionen bereitstellt, möchten Sie wahrscheinlich, dass das Framework diese Rückruffunktionen bei IRQL = PASSIVE_LEVEL aufruft, da einige Dateidaten, z. B. der Dateiname, seitenfähig sind.
Um eine Ausführungsebene bereitzustellen, muss Ihr Treiber einen Wert für das ExecutionLevel-Element der WDF_OBJECT_ATTRIBUTES Struktur eines Objekts angeben. Die Werte auf Ausführungsebene, die Ihr Treiber angeben kann, sind:
WdfExecutionLevelPassive
Das Framework ruft die Rückruffunktionen des Objekts bei IRQL = PASSIVE_LEVEL auf.
WdfExecutionLevelDispatch
Das Framework kann die Rückruffunktionen eines Objekts unter IRQL <= DISPATCH_LEVEL aufrufen. Wenn der Treiber die automatische Synchronisierung verwendet, ruft das Framework immer die Rückruffunktionen bei IRQL = DISPATCH_LEVEL auf.
WdfExecutionLevelInheritFromParent
Das Framework ruft den ExecutionLevel-Wert des Objekts vom übergeordneten Objekt ab.
Die Standardausführungsebene für Treiberobjekte ist WdfExecutionLevelDispatch. Die Standardausführungsebene für alle anderen Objekte ist WdfExecutionLevelInheritFromParent.
Weitere Informationen zu den Werten auf Ausführungsebene finden Sie unter WDF_EXECUTION_LEVEL.
Die folgende Tabelle zeigt die IRQL-Ebene, auf der das Framework die Rückruffunktionen eines Treibers für Warteschlangenobjekte und Dateiobjekte aufrufen kann.
| Synchronisierungsbereich | Ausführungsebene | IRQL von Warteschlangen- und Dateirückruffunktionen |
|---|---|---|
WdfSynchronizationScopeDevice |
WdfExecutionLevelPassive |
PASSIVE_LEVEL |
WdfSynchronizationScopeDevice |
WdfExecutionLevelDispatch |
DISPATCH_LEVEL |
WdfSynchronizationScopeQueue |
WdfExecutionLevelPassive |
PASSIVE_LEVEL |
WdfSynchronizationScopeQueue |
WdfExecutionLevelDispatch |
DISPATCH_LEVEL |
WdfSynchronizationScopeNone |
WdfExecutionLevelPassive |
PASSIVE_LEVEL |
WdfSynchronizationScopeNone |
WdfExecutionLevelDispatch |
<= DISPATCH_LEVEL |
Sie können die Ausführungsebene auf WdfExecutionLevelPassive oder WdfExecutionLevelDispatch für Treiber, Gerät, Datei, Warteschlange, Zeitgeber und allgemeine Objekte festlegen. Bei anderen Objekten können Sie nur WdfExecutionLevelInheritFromParent festlegen.
Geben Sie WdfExecutionLevelPassive an, wenn:
Die Rückruffunktionen Ihres Treibers müssen Framework-Methoden oder WDM-Routinen (Windows-Treibermodell) aufrufen, die Sie nur bei IRQL = PASSIVE_LEVEL aufrufen können.
Die Rückruffunktionen Ihres Treibers müssen auf pagebaren Code oder Daten zugreifen. Beispielsweise greifen Dateiobjektrückruffunktionen in der Regel auf seitenfähige Daten zu.
Anstatt WdfExecutionLevelPassive festzulegen, kann Ihr Treiber WdfExecutionLevelDispatch festlegen und eine Rückruffunktion bereitstellen, die Arbeitsaufgaben erstellt, wenn sie einige Vorgänge bei IRQL = PASSIVE_LEVEL verarbeiten muss.
Bevor Sie entscheiden, ob der Treiber die Ausführungsebene eines Objekts auf WdfExecutionLevelPassive festlegen soll, bestimmen Sie die IRQL, bei der Ihr Treiber und andere Treiber im Treiberstapel aufgerufen werden. Berücksichtigen Sie die folgenden Situationen:
Wenn sich Ihr Treiber oben im Kernelmodustreiberstapel befindet, ruft das System den Treiber in der Regel bei IRQL = PASSIVE_LEVEL auf. Der Client eines solchen Treibers kann ein UMDF-basierter Treiber oder eine Benutzermodusanwendung sein. Die Angabe von WdfExecutionLevelPassive wirkt sich nicht negativ auf die Leistung des Treibers aus, da das Framework die Aufrufe Ihres Treibers nicht in die Warteschlange für Arbeitselemente stellen muss, die bei IRQL = PASSIVE_LEVEL aufgerufen werden.
Wenn sich Ihr Treiber nicht ganz oben im Stapel befindet, ruft das System ihren Treiber wahrscheinlich nicht bei IRQL = PASSIVE_LEVEL auf. Daher muss das Framework die Aufrufe des Treibers in die Warteschlange für Arbeitsaufgaben stellen, die später bei IRQL = PASSIVE_LEVEL aufgerufen werden. Dieser Prozess kann zu einer schlechteren Treiberleistung führen, im Vergleich dazu, wenn die Rückruffunktionen Ihres Treibers bei IRQL <= DISPATCH_LEVEL aufgerufen werden könnten.
Für DPC-Objekte und für Timerobjekte, die keine Zeitgeber auf passiver Ebene darstellen, können Sie das AutomaticSerialization-Element der Konfigurationsstruktur nicht auf TRUE festlegen, wenn Sie die Ausführungsebene des übergeordneten Geräts auf WdfExecutionLevelPassive festlegen. Das Framework erwirbt die Rückrufsynchronisierungssperre des Geräteobjekts bei IRQL = PASSIVE_LEVEL. Daher können die Sperren nicht zum Synchronisieren der DPC- oder Timerobjektrückruffunktionen verwendet werden, die bei IRQL = DISPATCH_LEVEL ausgeführt werden müssen. In diesem Fall sollte Ihr Treiber Framework-Spin-Sperren in allen Geräte-, DPC- oder Timerobjektrückruffunktionen verwenden, die miteinander synchronisiert werden müssen.
Beachten Sie außerdem, dass Sie für Timerobjekte , die Zeitgeber auf passiver Ebene darstellen, das AutomaticSerialization-Element der Konfigurationsstruktur nur auf TRUE festlegen können, wenn die Ausführungsebene des übergeordneten Geräts auf WdfExecutionLevelPassive festgelegt ist.