Delen via


Automatische synchronisatie gebruiken

Bijna alle code in een frameworkstuurprogramma bevindt zich in gebeurtenisaanroepfuncties. Het framework synchroniseert automatisch de meeste callbackfuncties van een stuurprogramma als volgt:

Het framework implementeert deze automatische synchronisatie met behulp van een set interne synchronisatievergrendelingen. Het framework zorgt ervoor dat twee of meer threads dezelfde callback-functie niet tegelijkertijd kunnen aanroepen. Elke thread moet wachten totdat deze een synchronisatievergrendeling kan verkrijgen voordat een callback-functie wordt aangeroepen. (Indien nodig kunnen stuurprogramma's deze synchronisatievergrendelingen ook verkrijgen. Zie Framework-vergrendelingen gebruiken voor meer informatie.)

Het stuurprogramma moet objectspecifieke gegevens opslaan in de contextruimte van het object. Als uw stuurprogramma alleen frameworkgedefinieerde interfaces gebruikt, hebben alleen callbackfuncties die een ingang voor het object ontvangen toegang tot deze gegevens. Als het framework aanroepen synchroniseert met de callbackfuncties van het stuurprogramma, wordt slechts één callback-functie tegelijk aangeroepen. De contextruimte van het object is toegankelijk voor slechts één callback-functie tegelijk.

Tenzij uw stuurprogramma de verwerking van interrupts op passief niveau implementeert, moet code die onderbrekingen afhandelt en toegang heeft tot interruptgegevens, worden uitgevoerd op de IRQL (DIRQL) van het apparaat en vereist extra synchronisatie. Zie Interrupt-code synchroniseren voor meer informatie.

Als uw stuurprogramma automatische synchronisatie inschakelt van de callback-functies die I/O-aanvragen verwerken, synchroniseert het framework deze callback-functies zodat ze één voor één worden uitgevoerd. De volgende tabel bevat de callback-functies die door het framework worden gesynchroniseerd.

Objectsoort Gesynchroniseerde callbackfuncties

Wachtrij-object

Aanvraaghandlers, EvtIoQueueState, EvtIoResume, EvtIoStop

Object van een bestand

Alle callback-functies

Verzoekobject

EvtRequestCancel

Optioneel kan het framework deze callback-functies ook synchroniseren met elke interrupt-, DPC-, werkitem- en timerobjectaanroepfunctie die uw stuurprogramma biedt voor het apparaat (met uitzondering van de callback-functie EvtInterruptIsr van het interruptobject). Als u deze extra synchronisatie wilt inschakelen, moet het stuurprogramma het lid AutomaticSerialization van de configuratiestructuren van deze objecten instellen op TRUE.

Kortom, de functie voor automatische synchronisatie van het framework biedt de volgende functies:

  • Het framework synchroniseert altijd de PnP- en callbackfuncties voor energiebeheer van elk apparaat.

  • Optioneel kan het framework de aanvraaghandlers van een I/O-wachtrij synchroniseren en enkele extra callbackfuncties (zie de vorige tabel).

  • Een stuurprogramma kan het framework vragen om callback-functies te synchroniseren voor interrupt, DPC, werkitem en timerobjecten.

  • Stuurprogramma's moeten code synchroniseren die interrupt-verwerking regelt en toegang krijgt tot interruptgegevens door de technieken te gebruiken die worden beschreven in Synchronizing Interrupt Code.

  • Het framework synchroniseert niet de andere callbackfuncties van een stuurprogramma, zoals de callback-functie CompletionRoutine van het stuurprogramma of de callback-functies die door het I/O-doelobject worden gedefinieerd. In plaats daarvan biedt het framework extra vergrendelingen die stuurprogramma's kunnen gebruiken om deze callback-functies te synchroniseren.

Een synchronisatiebereik kiezen

U kunt ervoor kiezen om het framework alle callback-functies te laten synchroniseren die zijn gekoppeld aan alle I/O-wachtrijen van een apparaat. U kunt er ook voor kiezen om het framework afzonderlijk te laten synchroniseren met de callback-functies voor elk van de I/O-wachtrijen van een apparaat. De synchronisatieopties die beschikbaar zijn voor uw stuurprogramma zijn als volgt:

  • Synchronisatie op apparaatniveau

    Het framework synchroniseert de callback-functies voor alle I/O-wachtrijen van het apparaat, zodat ze één voor één worden uitgevoerd. Het framework bereikt deze synchronisatie door de synchronisatievergrendeling van het apparaat te verkrijgen voordat een callback-functie wordt aangeroepen.

  • Synchronisatie op wachtrijniveau

    Het framework synchroniseert de callback-functies voor elke afzonderlijke I/O-wachtrij, zodat ze één voor één worden uitgevoerd. Het framework bereikt deze synchronisatie door de synchronisatievergrendeling van de wachtrij te verkrijgen voordat een callback-functie wordt aangeroepen.

  • Geen synchronisatie

    Het framework synchroniseert de uitvoering van de callback-functies in de voorgaande tabel niet en verkrijgt geen synchronisatievergrendeling voordat de callback-functies worden aangeroepen. Als synchronisatie is vereist, moet het stuurprogramma dit opgeven.

Als u wilt opgeven of het framework synchronisatie op apparaatniveau, synchronisatie op wachtrijniveau of geen synchronisatie voor uw stuurprogramma moet bieden, geeft u een synchronisatiebereik op voor het stuurprogrammaobject, apparaatobjecten of wachtrijobjecten. Het SynchronizationScope-lid van de WDF_OBJECT_ATTRIBUTES structuur van een object identificeert het synchronisatiebereik van het object. De waarden voor het synchronisatiebereik die door het stuurprogramma kunnen worden opgegeven, zijn:

WdfSynchronizationScopeDevice
Het framework synchroniseert door de synchronisatievergrendeling van een apparaatobject te verkrijgen.

WdfSynchronizationScopeQueue
Het framework synchroniseert door de synchronisatievergrendeling van een wachtrijobject te verkrijgen.

WdfSynchronizationScopeNone
Het framework synchroniseert niet en verkrijgt geen synchronisatievergrendeling.

WdfSynchronizationScopeInheritFromParent
Het framework verkrijgt de SynchronizationScope-waarde van het object uit het ouderobject.

Over het algemeen raden we het gebruik van synchronisatie op apparaatniveau niet aan.

Zie WDF_SYNCHRONIZATION_SCOPE voor meer informatie over de waarden voor het synchronisatiebereik.

Het standaardsynchronisatiebereik voor stuurprogrammaobjecten is WdfSynchronizationScopeNone. Het standaardsynchronisatiebereik voor apparaat- en wachtrijobjecten is WdfSynchronizationScopeInheritFromParent.

Als u het framework wilt gebruiken om synchronisatie op apparaatniveau voor alle apparaten te bieden, stelt u SynchronizationScope in op WdfSynchronizationScopeDevice in de WDF_OBJECT_ATTRIBUTES structuur van het stuurprogrammaobject . Gebruik de standaardwaarde WdfSynchronizationScopeInheritFromParent voor elk apparaatobject .

Als u synchronisatie op apparaatniveau wilt bieden voor afzonderlijke apparaten, gebruikt u de standaardwaarde WdfSynchronizationScopeNone voor het stuurprogrammaobject . Stel SynchronizationScope in op WdfSynchronizationScopeDevice in de WDF_OBJECT_ATTRIBUTES structuur van afzonderlijke apparaatobjecten .

Als u wilt dat het framework synchronisatie op wachtrijniveau voor een apparaat biedt, kunt u de volgende technieken gebruiken:

  • Schakel voor frameworkversie 1.9 en hoger synchronisatie op wachtrijniveau in voor afzonderlijke wachtrijen door WdfSynchronizationScopeQueue in te stellen in de WDF_OBJECT_ATTRIBUTES structuur van het wachtrijobject. Deze techniek heeft de voorkeur.

  • U kunt ook de volgende stappen in alle frameworkversies gebruiken:

    1. Stel SynchronizationScope in op WdfSynchronizationScopeQueue in de WDF_OBJECT_ATTRIBUTES structuur van het apparaatobject .
    2. Gebruik de standaardwaarde WdfSynchronizationScopeInheritFromParent voor de wachtrijobjecten van elk apparaat.

Als u niet wilt dat het framework de callback-functies synchroniseert die de I/O-aanvragen van uw stuurprogramma verwerken, gebruikt u de standaard SynchronizationScope-waarde voor het stuurprogramma, apparaat en wachtrijobjecten van uw stuurprogramma. In dit geval synchroniseert het framework niet automatisch de I/O-aanvraagfuncties van het stuurprogramma. Het framework kan de callback-functies aanroepen op IRQL <= DISPATCH_LEVEL.

Als u een SynchronizationScope-waarde instelt, worden alleen de callback-functies gesynchroniseerd die de vorige tabel bevat. Als u wilt dat het framework ook de interrupt-, DPC-, werkitem- en timerobject-callbackfuncties van de bestuurder synchroniseert, stelt u het lid AutomaticSerialization van de configuratiestructuren van deze objecten in op TRUE.

U kunt AutomaticSerialization echter alleen instellen op TRUE als alle callback-functies die u wilt synchroniseren, worden uitgevoerd op dezelfde IRQL. Het kiezen van een uitvoeringsniveau, dat hierna wordt beschreven, kan leiden tot incompatibele IRQL-niveaus. In een dergelijke situatie moet de bestuurder frameworkvergrendelingen gebruiken in plaats van het instellen van AutomaticSerialization. Zie voor meer informatie over de configuratiestructuren voor interrupt-, DPC-, werkitem- en timerobjecten en voor meer informatie over beperkingen die van toepassing zijn op het instellen van AutomaticSerialization in deze structurenWDF_INTERRUPT_CONFIG, WDF_DPC_CONFIG, WDF_WORKITEM_CONFIG en WDF_TIMER_CONFIG.

Als u AutomaticSerialization instelt op TRUE, selecteert u synchronisatie op wachtrijniveau.

Een uitvoeringsniveau kiezen

Wanneer een stuurprogramma bepaalde typen frameworkobjecten maakt, kan het een uitvoeringsniveau voor het object opgeven. Het uitvoeringsniveau geeft de IRQL aan waarop het framework de callback-functies van het object aanroept die de I/O-aanvragen van een stuurprogramma verwerken.

Als een stuurprogramma een uitvoeringsniveau levert, heeft het opgegeven niveau invloed op de callback-functies voor wachtrij- en bestandsobjecten. Als het stuurprogramma gewoonlijk automatische synchronisatie gebruikt, roept het framework deze callback-functies aan bij IRQL = DISPATCH_LEVEL. Door een uitvoeringsniveau op te geven, kan het stuurprogramma afdwingen dat het framework deze callback-functies aanroept op IRQL = PASSIVE_LEVEL. In het framework worden de volgende regels gebruikt bij het instellen van de IRQL waarop de callback-functies voor wachtrij- en bestandsobjecten worden aangeroepen:

  • Als een stuurprogramma automatische synchronisatie gebruikt, worden de callback-functies voor wachtrij- en bestandsobjecten aangeroepen op IRQL = DISPATCH_LEVEL, tenzij het stuurprogramma het framework vraagt om de callback-functies op IRQL = PASSIVE_LEVEL aan te roepen.

  • Als een stuurprogramma geen automatische synchronisatie gebruikt en geen uitvoeringsniveau opgeeft, kunnen de callback-functies van het stuurprogramma en de callback-functies voor bestandsobjecten worden aangeroepen op IRQL <= DISPATCH_LEVEL.

Als uw stuurprogramma callback-functies voor bestandsobjecten biedt, wilt u waarschijnlijk dat het framework deze callback-functies aanroept op IRQL = PASSIVE_LEVEL omdat sommige bestandsgegevens, zoals de bestandsnaam, paginabaar zijn.

Als u een uitvoeringsniveau wilt opgeven, moet uw stuurprogramma een waarde opgeven voor het lid ExecutionLevel van de WDF_OBJECT_ATTRIBUTES structuur van een object. De waarden op uitvoeringsniveau die door het stuurprogramma kunnen worden opgegeven, zijn:

WdfExecutionLevelPassive
Het framework roept de callback-functies van het object aan bij IRQL = PASSIVE_LEVEL.

WdfExecutionLevelDispatch
Het framework kan de callback-functies van het object aanroepen op IRQL <= DISPATCH_LEVEL. Als het stuurprogramma automatische synchronisatie gebruikt, roept het framework altijd de callback-functies aan bij IRQL = DISPATCH_LEVEL.

WdfExecutionLevelInheritFromParent
Het framework verkrijgt de ExecutionLevel-waarde van het object uit het ouderobject.

Het standaarduitvoeringsniveau voor stuurprogrammaobjecten is WdfExecutionLevelDispatch. Het standaarduitvoeringsniveau voor alle andere objecten is WdfExecutionLevelInheritFromParent.

Zie WDF_EXECUTION_LEVEL voor meer informatie over de waarden op uitvoeringsniveau.

In de volgende tabel ziet u het IRQL-niveau waarop het framework de callbackfuncties van een stuurprogramma kan aanroepen voor wachtrijobjecten en bestandsobjecten.

Synchronisatiebereik Uitvoeringsniveau IRQL van de Queue- en Bestandscallbackfuncties

WdfSynchronizationScopeDevice

WdfExecutionLevelPassive

PASSIVE_LEVEL

WdfSynchronizationScopeDevice

WdfExecutionLevelDispatch

DISPATCH_LEVEL

WdfSynchronizationScopeQueue

WdfExecutionLevelPassive

PASSIVE_LEVEL

WdfSynchronizationScopeQueue

WdfExecutionLevelDispatch

DISPATCH_LEVEL

WdfSynchronizationScopeNone

WdfExecutionLevelPassive

PASSIVE_LEVEL

WdfSynchronizationScopeNone

WdfExecutionLevelDispatch

<= DISPATCH_NIVEAU

U kunt het uitvoeringsniveau instellen op WdfExecutionLevelPassive of WdfExecutionLevelDispatch voor stuurprogramma,apparaat, bestand, wachtrij, timer en algemene objecten. Voor andere objecten is alleen WdfExecutionLevelInheritFromParent toegestaan.

U moet WdfExecutionLevelPassive opgeven als:

  • De callback-functies van uw stuurprogramma moeten frameworkmethoden of WDM-routines (Windows Driver Model) aanroepen die u alleen kunt aanroepen op IRQL = PASSIVE_LEVEL.

  • De callbackfuncties van uw stuurprogramma moeten toegang hebben tot paginabare code of gegevens. Bijvoorbeeld: callback-functies voor bestandsobjecten hebben doorgaans toegang tot paginabare gegevens.

In plaats van WdfExecutionLevelPassive in te stellen, kan uw stuurprogramma WdfExecutionLevelDispatch instellen en een callback-functie opgeven waarmee werkitems worden gemaakt als bepaalde bewerkingen op IRQL = PASSIVE_LEVEL moeten worden verwerkt.

Voordat u besluit of het stuurprogramma het uitvoeringsniveau van een object moet instellen op WdfExecutionLevelPassive, bepaalt u de IRQL waarop uw stuurprogramma en andere stuurprogramma's in de stuurprogrammastack worden aangeroepen. Houd rekening met de volgende situaties:

  • Als uw stuurprogramma zich boven aan de kernelmodusstuurprogrammastack bevindt, roept het systeem meestal het stuurprogramma aan bij IRQL = PASSIVE_LEVEL. De client van een dergelijk stuurprogramma kan een op UMDF gebaseerd stuurprogramma of een toepassing in de gebruikersmodus zijn. Het specificeren van WdfExecutionLevelPassive beïnvloedt de prestaties van het stuurprogramma niet negatief, omdat het framework niet de noodzaak heeft om de aanroepen van het stuurprogramma voor werkitems die op IRQL = PASSIVE_LEVEL worden uitgevoerd in de wachtrij te plaatsen.

  • Als uw stuurprogramma zich niet boven aan de stack bevindt, roept het systeem uw stuurprogramma waarschijnlijk niet aan bij IRQL = PASSIVE_LEVEL. Daarom moet het framework de aanroepen van het stuurprogramma in de wachtrij plaatsen voor werkitems, die later worden aangeroepen bij IRQL = PASSIVE_LEVEL. Dit proces kan leiden tot slechte prestaties van stuurprogramma's, vergeleken met het toestaan van de callback-functies van uw stuurprogramma op IRQL <= DISPATCH_LEVEL.

Voor DPC-objecten en voor timerobjecten die geen timers op passief niveau vertegenwoordigen, kunt u het lid AutomaticSerialization van de configuratiestructuur niet instellen op TRUE als u het uitvoeringsniveau van het bovenliggende apparaat instelt op WdfExecutionLevelPassive. Het framework verkrijgt de callbacksynchronisatievergrendelingen van het apparaatobject op IRQL = PASSIVE_LEVEL. Daarom kunnen de vergrendelingen niet worden gebruikt om de callbackfuncties van het DPC- of timerobject te synchroniseren, die uitgevoerd moeten worden op IRQL = DISPATCH_LEVEL. In dit geval moet uw driver framework spin-vergrendelingen gebruiken in de callbackfuncties van apparaat-, DPC- of timerobjecten, die met elkaar moeten worden gesynchroniseerd.

Houd er ook rekening mee dat voor timerobjecten die wel timers op passief niveau vertegenwoordigen, u het lid AutomaticSerialization van de configuratiestructuur alleen op TRUE kunt instellen als het uitvoeringsniveau van het bovenliggende apparaat is ingesteld op WdfExecutionLevelPassive.