Condividi tramite


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 di memoria non paginata allocato dal driver.

Quando il driver chiama KeInitializeEvent, deve passare un puntatore alla memoria 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 definito evento di autoclearing, perché il relativo stato segnalato viene reimpostato automaticamente ogni volta che viene soddisfatta un'attesa.

  • NotificationEvent

    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 del Not-Signaled, ovvero è presente una chiamata a KeClearEvent o KeResetEvent con il puntatore di evento specificato.

Pochi driver di dispositivo o intermedi hanno un singolo thread dedicato al driver, per non parlare di un insieme di thread che potrebbero sincronizzare le loro 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 gli IRPs che un driver crea con IoBuildSynchronousFsdRequest o IoBuildDeviceIoControlRequest è spesso inizializzato come NotificationEvent perché il chiamante attenderà l'evento per ricevere una notifica che la sua 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 runtime 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 all'archiviazione fornita dal driver per l'oggetto evento inizializzato.

  2. Altre routine del driver eseguono le operazioni di I/O sul dispositivo 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 incremento di priorità determinato dal driver per il thread (Increment, come illustrato nella figura precedente) e un parametro booleano Wait impostato su FALSE. La chiamata a KeSetEvent imposta l'oggetto evento sullo stato Signaled, modificando così lo stato del thread in attesa in modo che sia 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 runtime di integrazione superiore.

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

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

Considerare le linee guida seguenti per impostare il parametro WaitsuKeSetEvent:

Una routine del driver pageable o di thread visualizzabile da pagina 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 che viene eseguita in IRQL = DISPATCH_LEVEL non può attendere per un intervallo di tempo diverso da zero su qualsiasi oggetto dispatcher senza causare l'arresto del 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 dei driver standard, vedere Gestione delle priorità hardware.

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

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

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