Definizione e utilizzo di un oggetto evento

Qualsiasi driver che usa un oggetto evento deve chiamare KeInitializeEvent, IoCreateNotificationEvent o IoCreateSynchronizationEvent prima di attendere, impostare, cancellare o reimpostare l'evento. La figura seguente illustra come un driver con un thread può usare un oggetto evento per la sincronizzazione.

diagramma che illustra l'attesa di un oggetto evento.

Come illustrato nella figura precedente, tale driver deve fornire lo spazio di archiviazione per l'oggetto evento, che deve essere residente. Il driver può usare l'estensione del dispositivo di un oggetto dispositivo creato dal driver, l'estensione del controller se usa un oggetto controller o un pool non di paging allocato dal driver.

Quando il driver chiama KeInitializeEvent, deve passare un puntatore alla risorsa di archiviazione residente del driver per l'oggetto evento. Inoltre, il chiamante deve specificare lo stato iniziale (segnalato o non segnalato) per l'oggetto evento. Il chiamante deve anche specificare il tipo di evento, che può essere uno dei seguenti:

  • SynchronizationEvent

    Quando un evento di sincronizzazione è impostato sullo stato Segnalato, un singolo thread in attesa che l'evento venga reimpostato su Not-Signaled diventa idoneo per l'esecuzione e lo stato dell'evento viene reimpostato automaticamente su Not-Signaled.

    Questo tipo di evento viene talvolta chiamato evento di cancellazione automatica, perché lo stato segnalato viene reimpostato automaticamente ogni volta che viene soddisfatta un'attesa.

  • Evento di notifica

    Quando un evento di notifica è impostato sullo stato Segnalato, tutti i thread in attesa che l'evento venga reimpostato su Not-Signaled diventano idonei per l'esecuzione e l'evento rimane nello stato Segnalato fino a quando non si verifica una reimpostazione esplicita di Not-Signaled, ovvero è presente una chiamata a KeClearEvent o KeResetEvent con il puntatoredi evento specificato.

Pochi driver di dispositivo o intermedi dispongono di un singolo thread dedicato al driver, e non solo un set di thread che potrebbero sincronizzare le operazioni attendendo un evento che protegge una risorsa condivisa.

La maggior parte dei driver che usano oggetti evento per attendere il completamento di un'operazione di I/O imposta il tipo di input su NotificationEvent quando chiamaNo KeInitializeEvent. Un oggetto evento configurato per i runtime di integrazione creati da un driver con IoBuildSynchronousFsdRequest o IoBuildDeviceIoControlRequest viene quasi sempre inizializzato come notificationEvent perché il chiamante attenderà l'evento per la notifica che la richiesta è stata soddisfatta da uno o più driver di livello inferiore.

Dopo che il driver è stato inizializzato, il thread dedicato al driver, se presente, e altre routine possono sincronizzare le operazioni sull'evento. Ad esempio, un driver con un thread che gestisce l'accodamento dei provider di integrazione, ad esempio il driver del controller floppy di sistema, potrebbe sincronizzare l'elaborazione IRP in un evento, come illustrato nella figura precedente:

  1. Il thread, che ha dequeuato un IRP per l'elaborazione nel dispositivo, chiama KeWaitForSingleObject con un puntatore alla risorsa di archiviazione fornita dal driver per l'oggetto evento inizializzato.

  2. Altre routine driver eseguono il dispositivo le operazioni di I/O necessarie per soddisfare l'IRP e, al termine di queste operazioni, la routine DpcForIsr del driver chiama KeSetEvent con un puntatore all'oggetto evento, un boost di priorità determinato dal driver per il thread (Increment, come illustrato nella figura precedente) e un'attesa booleana impostata su FALSE. La chiamata a KeSetEvent imposta l'oggetto evento sullo stato Signaled, modificando così lo stato del thread in attesa su pronto.

  3. Il kernel invia il thread per l'esecuzione non appena è disponibile un processore, ovvero nessun altro thread con priorità più alta è attualmente nello stato pronto e non sono presenti routine in modalità kernel da eseguire in un irQL superiore.

    Il thread ora può completare l'IRP se DpcForIsr non ha chiamato IoCompleteRequest con L'IRP già e può annullare la coda di un altro IRP da elaborare nel dispositivo.

La chiamata a KeSetEvent con il parametro Wait impostato su TRUE indica l'intenzione del chiamante di chiamare immediatamente una routine KeWaitForSingleObject o KeWaitForMultipleObjects per il ritorno da KeSetEvent.

Considerare le linee guida seguenti per impostare il parametro WaitsuKeSetEvent:

Una routine di driver pageable o thread eseguibile da paging eseguita in IRQL < DISPATCH_LEVEL non deve mai chiamare KeSetEvent con il parametro Wait impostato su TRUE. Tale chiamata causa un errore di pagina irreversibile se il chiamante viene eseguito il paging tra le chiamate a KeSetEvent e KeWaitForSingleObject o KeWaitForMultipleObjects.

Qualsiasi routine del driver standard eseguita in IRQL = DISPATCH_LEVEL non può attendere un intervallo diverso da zero su qualsiasi oggetto dispatcher senza arrestare il sistema. Tuttavia, tale routine può chiamare KeSetEvent durante l'esecuzione in un IRQL minore o uguale a DISPATCH_LEVEL.

Per un riepilogo dei runtime di integrazione in cui vengono eseguite le routine del driver standard, vedere Gestione delle priorità hardware.

KeResetEvent restituisce lo stato precedente di un determinato evento: indica se è stato impostato su Signaled o meno quando si è verificata la chiamata a KeResetEvent . KeClearEvent imposta semplicemente lo stato dell'evento specificato su Non segnalato.

Considerare le linee guida seguenti per quando chiamare le routine di supporto precedenti:

Per ottenere prestazioni migliori, ogni driver deve chiamare KeClearEvent a meno che il chiamante non richieda le informazioni restituite da KeResetEvent per determinare le operazioni da eseguire successivamente.