Definiera och använda ett händelseobjekt

Alla drivrutiner som använder ett händelseobjekt måste anropa KeInitializeEvent, IoCreateNotificationEventeller IoCreateSynchronizationEvent innan den väntar, anger, rensar eller återställer händelsen. Följande bild visar hur en drivrutin med en tråd kan använda ett händelseobjekt för synkronisering.

diagram som illustrerar väntan på ett händelseobjekt.

Som föregående bild visar måste en sådan drivrutin tillhandahålla lagringen för händelseobjektet, som måste vara permanent. Drivrutinen kan använda enhetstillägget för ett enhetsobjekt som skapats av drivrutinen, kontrollanttillägget om det använder ett kontrollantobjekteller en pool som inte har allokerats av drivrutinen.

När drivrutinen anropar KeInitializeEventmåste den skicka en pekare till drivrutinens residenta lagring för händelseobjektet. Dessutom måste anroparen ange det initiala tillståndet (signalerat eller inte signalerat) för händelseobjektet. Anroparen måste också ange händelsetypen, vilket kan vara något av följande:

  • SynkroniseringHändelse

    När en synkroniseringshändelse är inställd på tillståndet Signaled, blir en enda tråd som väntar på att händelsen ska återställas till Not-Signaled berättigad till körning och händelsens tillstånd återställs automatiskt till Not-Signaled.

    Den här typen av händelse kallas ibland för en autoclearing-händelse, eftersom dess signalerade läge återställs automatiskt varje gång en väntning avslutas.

  • Notifikationshändelse

    När en meddelandehändelse är inställd på signaltillståndet, blir alla trådar som väntade på att händelsen skulle återställas till Not-Signaled berättigade att få köras. Händelsen förblir i signaltillståndet tills en explicit återställning till Not-Signaled inträffar: det vill säga att det sker ett anrop till KeClearEvent eller KeResetEvent med den angivna Händelse pekaren.

Få enhetsdrivrutiner eller mellanliggande drivrutiner har en enda drivrutinsspecifik tråd, för att inte tala om en uppsättning trådar som kan synkronisera deras åtgärder genom att vänta på en händelse som skyddar en delad resurs.

De flesta drivrutiner som använder händelseobjekt för att vänta tills en I/O-åtgärd har slutförts anger indata Typ till NotificationEvent när de anropar KeInitializeEvent. Ett händelseobjekt som konfigurerats för IRP:er som en drivrutin skapar med IoBuildSynchronousFsdRequest eller IoBuildDeviceIoControlRequest initieras nästan alltid som en NotificationEvent eftersom anroparen väntar på händelsen för att få ett meddelande om att dess begäran har uppfyllts av en eller flera drivrutiner på lägre nivå.

När drivrutinen har initierat sig själv kan dess drivrutinsspecifika tråd, om någon, och andra rutiner synkronisera sina åtgärder på händelsen. En drivrutin med en tråd som hanterar köer för IRP, såsom drivrutinen för systemets diskettkontroller, kan synkronisera IRP-bearbetningen på en händelseflagga, som visas i föregående bild.

  1. Tråden, som har tagit bort en IRP från kön för bearbetning på enheten, anropar KeWaitForSingleObject med en pekare till lagring som tillhandahålls av drivrutinen för det initierade händelseobjektet.

  2. Andra drivrutiner utför de I/O-åtgärder som krävs för att uppfylla IRP:n, och när dessa åtgärder är slutförda gör drivrutinens rutin DpcForIsr ett anrop till KeSetEvent med en pekare till händelseobjektet, en drivrutinsbestämd prioritetsökning för tråden (Ökning, som visas i föregående bild), och en boolesk inställning Vänta satt till FALSE. Anrop av KeSetEvent ställer in händelseobjektet till tillståndet 'Signalering', vilket därmed ändrar den väntande trådens tillstånd till redo.

  3. Kärnan skickar tråden för körning så snart en processor är tillgänglig: det vill säga att ingen annan tråd med högre prioritet för närvarande är i redo-tillstånd och det inte finns några kärn-lägesrutiner som ska köras på en högre IRQL.

    Tråden kan nu slutföra IRP om DpcForIsr inte redan har anropat IoCompleteRequest med IRP, och kan sedan dequeuera en annan IRP som ska bearbetas på enheten.

Att anropa KeSetEvent med parametern Wait inställd på TRUE anger anroparens avsikt att omedelbart anropa en KeWaitForSingleObject eller KeWaitForMultipleObjects supportrutin vid retur från KeSetEvent.

Överväg följande riktlinjer för att ange parameternWaittillKeSetEvent:

En paginerbar tråd eller paginerbar drivrutinsrutin som körs på IRQL < DISPATCH_LEVEL bör aldrig anropa KeSetEvent med parametern Wait inställd på TRUE. Ett sådant anrop orsakar ett allvarligt sidfel om anroparen råkar bli utspnad mellan anropen till KeSetEvent och KeWaitForSingleObject eller KeWaitForMultipleObjects.

Standarddrivrutiner som körs på IRQL = DISPATCH_LEVEL kan inte vänta på ett icke-noll intervall på några växelobjekt utan att riskera systemets stabilitet. En sådan rutin kan dock anropa KeSetEvent när den körs på en IRQL som är mindre än eller lika med DISPATCH_LEVEL.

En sammanfattning av de IRQL:er där standarddrivrutinsrutiner körs finns i Hantera maskinvaruprioriteringar.

KeResetEvent returnerar det tidigare tillståndet för en viss Händelse: om den var inställd på Signaled eller inte när anropet till KeResetEvent inträffade. KeClearEvent anger helt enkelt tillståndet för den angivna Händelse till Not-Signaled.

Överväg följande riktlinjer för när du ska anropa föregående supportrutiner:

För bättre prestanda bör varje drivrutin anropa KeClearEvent om inte anroparen behöver den information som returneras av KeResetEvent för att avgöra vad som ska göras härnäst.