Introduzione agli oggetti Dispatcher del kernel

Il kernel definisce un set di tipi di oggetto denominati oggetti dispatcher del kernel o semplicemente oggetti dispatcher. Gli oggetti Dispatcher includono oggetti timer, oggetti evento, oggetti semafori, oggetti mutex e oggetti thread.

I driver possono usare gli oggetti dispatcher come meccanismi di sincronizzazione all'interno di un contesto di thread non arbiverso durante l'esecuzione in IRQL uguale a PASSIVE_LEVEL.

Stati dell'oggetto Dispatcher

Ogni tipo di oggetto dispatcher definito dal kernel ha uno stato impostato su Signaled o impostato su Not-Signaled.

Un gruppo di thread può sincronizzare le operazioni se uno o più thread chiamano KeWaitForSingleObject, KeWaitForMutexObject oKeWaitForMultipleObjects. Queste funzioni accettano puntatori a oggetti dispatcher come input e attendere fino a quando un'altra routine o thread imposta uno o più oggetti dispatcher sullo stato Signaled.

Quando un thread chiama KeWaitForSingleObject per attendere un oggetto dispatcher (o KeWaitForMutexObject per un mutex ), il thread viene inserito in uno stato di attesa fino a quando l'oggetto dispatcher non viene impostato sullo stato Signaled. Un thread può chiamare KeWaitForMultipleObjects per attendere qualsiasi oggetto, o per tutti, di un set di oggetti dispatcher da impostare su Signaled.

Ogni volta che un oggetto dispatcher è impostato sullo stato Signaled, il kernel modifica lo stato di qualsiasi thread in attesa che tale oggetto sia pronto. I timer di sincronizzazione e gli eventi di sincronizzazione sono eccezioni a questa regola. Quando viene segnalato un evento di sincronizzazione o un timer, viene impostato un solo thread in attesa sullo stato pronto. Per altre informazioni, vedere Oggetti timer e controller di dominio e oggetti evento. Un thread nello stato pronto verrà pianificato in base alla priorità del thread di runtime corrente e alla disponibilità corrente dei processori per qualsiasi thread con tale priorità.

Quando i driver possono attendere gli oggetti Dispatcher?

In generale, i driver possono attendere che gli oggetti dispatcher vengano impostati solo se almeno una delle circostanze seguenti è true:

  • Il driver viene eseguito in un contesto di thread non arbiverso.

    Vale a dire, è possibile identificare il thread che immetterà uno stato di attesa. In pratica, le uniche routine driver eseguite in un contesto di thread non arbiverso sono DriverEntry, AddDevice, Reinitialize e Scarica routine di qualsiasi driver, oltre alle routine di invio di driver di livello più alto. Tutte queste routine vengono chiamate direttamente dal sistema.

  • Il driver esegue una richiesta di I/O completamente sincrona.

    Ovvero, nessuna coda di driver durante la gestione della richiesta di I/O e nessun driver restituisce fino al termine della gestione della richiesta.

Inoltre, un driver non può immettere uno stato di attesa se è in esecuzione in o superiore a IRQL uguale a DISPATCH_LEVEL.

In base a queste limitazioni, è necessario usare le regole seguenti:

  • DriverEntry, AddDevice, Reinitialize e Scarica routine di qualsiasi driver possono attendere gli oggetti dispatcher.

  • Le routine di invio di un driver di livello più alto possono attendere gli oggetti dispatcher.

  • Le routine di invio dei driver di livello inferiore possono attendere gli oggetti di invio, se l'operazione di I/O è sincrona, ad esempio creare, scaricare, arrestare e chiudere operazioni, alcune operazioni di controllo I/O del dispositivo e alcune operazioni di alimentazione e PnP.

  • Le routine di invio dei driver di livello inferiore non possono attendere il completamento di operazioni di I/O asincrone.

  • Una routine driver in esecuzione in corrispondenza o superiore a IRQL DISPATCH_LEVEL non deve attendere che un oggetto dispatcher sia impostato sullo stato Signaled.

  • Un driver non deve tentare di attendere che un oggetto dispatcher sia impostato sullo stato segnalato per il completamento di un'operazione di trasferimento verso o da un dispositivo di paging.

  • Le routine di invio driver che eseggono le richieste di lettura/scrittura in genere non possono attendere che un oggetto dispatcher sia impostato sullo stato segnalato.

  • Una routine di invio per una richiesta di controllo I/O del dispositivo può attendere che un oggetto dispatcher sia impostato sullo stato segnalato solo se il tipo di trasferimento per il codice di controllo I/O è METHOD_BUFFERED.

  • I driver miniport SCSI non devono usare oggetti dispatcher kernel. I driver miniport SCSI devono chiamare solo routine della libreria di porte SCSI.

Ogni altra routine del driver standard viene eseguita in un contesto di thread arbitrario: quella di qualsiasi thread sia corrente quando la routine del driver viene chiamata per elaborare un'operazione in coda o per gestire un interruzione del dispositivo. Inoltre, la maggior parte delle routine di driver standard viene eseguita in un irQL generato, in DISPATCH_LEVEL o per i driver di dispositivo, in DIRQL.

Se necessario, un driver può creare un thread dedicato al dispositivo, che può attendere le altre routine del driver (ad eccezione di una routine ISR o SynchCritSection ) per impostare un oggetto dispatcher sullo stato segnalato e reimpostare lo stato di Not-Signaled.

Come linee guida generali, se si prevede che il nuovo driver di dispositivo spesso deve bloccarsi per più di 50 microsecondi mentre attende le modifiche dello stato del dispositivo durante le operazioni di I/O, prendere in considerazione l'implementazione di un driver con un thread dedicato al dispositivo. Se il driver del dispositivo è anche un driver di livello più alto, prendere in considerazione l'uso di thread di lavoro di sistema e l'implementazione di una o più routine di callback del thread di lavoro. Vedere PsCreateSystemThread e Gestione di code interlocked con un thread Driver-Created.