Dela via


Introduktion till Kernel Dispatcher-objekt

Kerneln definierar en uppsättning objekttyper som kallas kernel dispatcher-objekt eller bara dispatcher-objekt. Dispatcher-objekt inkluderar tidsinställda objekt, händelseobjekt, semaforobjekt, mutex-objekt och trådobjekt.

Drivrutiner kan använda dispatcher-objekt som synkroniseringsmekanismer i en icke-arbiträr trådkontext medan de körs på en IRQL-nivå som är lika med PASSIVE_LEVEL.

Dispatcher-objekttillstånd

Varje kerneldefinierad dispatcher-objekttyp har ett tillstånd som antingen är inställt på Signaled eller inställd på Not-Signaled.

En grupp trådar kan synkronisera sina åtgärder om en eller flera trådar anropar KeWaitForSingleObject, KeWaitForMutexObject eller KeWaitForMultipleObjects. Dessa funktioner tar dispatcher-objektpekare som indata och väntar tills en annan rutin eller tråd anger ett eller flera dispatcher-objekt till tillståndet Signaled.

När en tråd anropar KeWaitForSingleObject för att vänta på ett dispatcher-objekt (eller KeWaitForMutexObject för en mutex) placeras tråden i väntetillstånd tills dispatcher-objektet har angetts till tillståndet Signaled. En tråd kan anropa KeWaitForMultipleObjects för att vänta på att någon eller alla av en uppsättning dispatcher-objekt ska anges till Signaled.

När ett dispatcher-objekt är inställt på tillståndet Signaled ändrar kerneln tillståndet för alla trådar som väntar på att objektet ska vara klart. (Synkroniseringstimers och synkroniseringshändelser är undantag från den här regeln. När en synkroniseringshändelse eller timer signaleras är endast en väntande tråd inställd på det klara tillståndet. Mer information finns i Timer-objekt och DPC:er och händelseobjekt.) En tråd i klart tillstånd schemaläggs att köras enligt den aktuella körningstrådens prioritet och den aktuella tillgängligheten för processorer för alla trådar med den prioriteten.

När kan drivrutiner vänta på dispatcher-objekt?

I allmänhet kan drivrutiner vänta på att dispatcher-objekt ska konfigureras endast om minst en av följande omständigheter är uppfylld:

  • Drivrutinen körs i en icke-arbiträr trådkontext.

    Det vill säga att du kan identifiera den tråd som går in i ett vänteläge. I praktiken är de enda drivrutinsrutiner som körs i en icke-linjär trådkontext rutinerna DriverEntry, AddDevice, Reinitialize och Unload för alla drivrutiner, plus sändningsrutinerna för drivrutiner på högsta nivå. Alla dessa rutiner anropas direkt av systemet.

  • Drivrutinen utför en fullständigt synkron I/O-begäran.

    Det vill säga: ingen drivrutin köar några operationer när I/O-begäran hanteras, och ingen drivrutin returnerar förrän drivrutinen under den har hanterat begäran.

Dessutom kan en drivrutin inte ange ett väntetillstånd om den körs vid eller över IRQL lika med DISPATCH_LEVEL.

Baserat på dessa begränsningar måste du använda följande regler:

  • Rutinerna DriverEntry, AddDevice, Reinitialize och Unload för alla drivrutiner kan vänta på dispatcher-objekt.

  • Sändningsrutinerna för en drivrutin på högsta nivå kan vänta på dispatcher-objekt.

  • Händelsesrutinerna för drivrutiner på lägre nivå kan vänta på distributionsobjekt, om I/O-operationen är synkron, till exempel skapa-, tömnings-, avstängnings- och stängningsoperationer, vissa enhetsstyrningsoperationer för I/O och vissa PnP- och strömhanteringsoperationer.

  • Lägre nivåers drivrutins rutiner kan inte vänta på ett dispatcher-objekt för att slutföra asynkrona I/O-operationer.

  • En drivrutin som körs vid eller över IRQL-DISPATCH_LEVEL får inte vänta tills ett dispatcher-objekt har angetts till tillståndet Signaled.

  • En drivrutin får inte försöka vänta tills ett dispatcher-objekt har ställts till signalerat läge för att slutföra en överföringsåtgärd till eller från en paging-enhet.

  • Rutiner för drivrutinssändning som betjänar läs-/skrivbegäranden kan vanligtvis inte vänta tills ett dispatcher-objekt har angetts till tillståndet Signaled.

  • En sändningsrutin för en enhets-I/O-kontrollbegäran kan vänta för att ett dispatcher-objekt ska ställas in i signalerat läge endast om överföringstypen för I/O-kontrollkoden är METHOD_BUFFERED.

  • SCSI-miniportdrivrutiner bör inte använda kernel dispatcher-objekt. SCSI-miniportdrivrutiner bör endast anropa stödprocedurer för SCSI-portdrivrutiner.

Alla andra vanliga drivrutinsrutiner körs i en godtycklig trådkontext: den tråd som råkar vara aktuell när drivrutinen anropas för att bearbeta en köad åtgärd eller för att hantera ett enhetsavbrott. Dessutom körs de flesta vanliga drivrutinsrutiner på en upphöjd IRQL, antingen på DISPATCH_LEVEL eller för enhetsdrivrutiner, på DIRQL.

Vid behov kan en drivrutin skapa en enhetsdedikerad tråd som kan vänta på förarens andra rutiner (förutom en ISR- eller SynchCritSection-rutin ) för att ange ett dispatcher-objekt till tillståndet Signaled och återställa till Not-Signaled tillstånd.

Om du förväntar dig att den nya enhetsdrivrutinen ofta behöver stanna längre än 50 mikrosekunder medan den väntar på ändringar i enhetstillståndet under I/O-åtgärder bör du överväga att implementera en drivrutin med en enhetsdedikerad tråd. Om enhetsdrivrutinen också är en drivrutin på högsta nivå bör du överväga att använda systemarbetstrådar och implementera en eller flera återanropsrutiner för arbetstrådar. Se PsCreateSystemThread och Managing Interlocked Queues with a Driver-Created Thread.