Condividi tramite


Uso di una routine IoTimer

Mentre il timer per l'oggetto dispositivo associato è abilitato, la routine IoTimer viene chiamata circa una volta al secondo. Tuttavia, poiché gli intervalli in cui ogni routine IoTimer viene chiamata dipende dalla risoluzione del clock di sistema, non si presuppone che una routine IoTimer venga chiamata esattamente su un limite di un secondo.

Nota Una routine IoTimer , come tutte le routine DPC, viene chiamata in IRQL = DISPATCH_LEVEL. Durante l'esecuzione di una routine DPC, non è possibile eseguire tutti i thread nello stesso processore. Gli sviluppatori di driver devono progettare attentamente le routine IoTimer per l'esecuzione per un breve periodo di tempo possibile.

Forse l'uso più comune per una routine IoTimer consiste nel timeout delle operazioni di I/O del dispositivo per un IRP. Si consideri lo scenario seguente per l'uso di una routine IoTimer come timer in esecuzione all'interno di un driver di dispositivo:

  1. All'avvio del dispositivo, il driver inizializza un contatore timer nell'estensione del dispositivo su -1, che indica nessuna operazione di I/O corrente del dispositivo e chiama IoStartTimer appena prima che restituisca STATUS_SUCCESS.

    Ogni volta che viene chiamata la routine IoTimer , controlla se il contatore timer è -1 e, in tal caso, restituisce il controllo .

  2. La routine StartIo del driver inizializza il contatore timer nell'estensione del dispositivo a un limite superiore, oltre a un secondo aggiuntivo nel caso in cui la routine IoTimer sia stata appena eseguita. Usa quindi KeSynchronizeExecution per chiamare una routine SynchCritSection_1 , che programma il dispositivo fisico per l'operazione richiesta dall'IRP corrente.

  3. L'ISR del driver reimposta il contatore del timer su -1 prima di accodare la routine DpcForIsr del driver o una routine CustomDpc .

  4. Ogni volta che viene chiamata la routine IoTimer , controlla se il contatore timer è stato reimpostato dall'ISR su -1 e, in tal caso, restituisce il controllo . In caso contrario, la routine IoTimer usa KeSynchronizeExecution per chiamare una routine SynchCritSection_2 , che regola il contatore timer in base a un numero determinato di driver di secondi.

  5. La routine SynchCritSection_2 restituisce TRUE alla routine IoTimer purché la richiesta corrente non sia ancora scaduta. Se il contatore timer passa a zero, la routine SynchCritSection_2 reimposta il contatore timer su un valore di reset-timeout determinato dal driver, imposta un flag previsto per se stesso (e per DpcForIsr) nell'area di contesto, tenta di reimpostare il dispositivo e restituisce TRUE.

    La routine SynchCritSection_2 verrà chiamata di nuovo se si verifica anche il timeout dell'operazione di reimpostazione nel dispositivo, quando restituisce FALSE. Se il ripristino ha esito positivo, la routine DpcForIsr determina che il dispositivo è stato reimpostato dal flag previsto per la reimpostazione e ritenta la richiesta, ripetendo le azioni della routine StartIo come descritto nel passaggio 2.

  6. Se la routine SynchCritSection_2 restituisce FALSE, la routine IoTimer presuppone che il dispositivo fisico sia in uno stato sconosciuto perché un tentativo di reimpostazione non è già riuscito. In queste circostanze, la routine IoTimer accoda una routine CustomDpc e restituisce . Questa routine CustomDpc registra un errore di I/O del dispositivo, chiama IoStartNextPacket, non riesce l'IRP corrente e restituisce.

Se l'ISR del driver di dispositivo reimposta il contatore timer condiviso su -1, come descritto nel passaggio 3, la routine DpcForIsr del driver completa l'elaborazione di I/O basata su interrupt dell'I/O corrente. Il contatore timer di reimpostazione indica che l'operazione di I/O del dispositivo non è scaduta, quindi la routine IoTimer non deve modificare il contatore timer.

Nella maggior parte dei casi, la routine SynchCritSection_2 precedente decrementa semplicemente il contatore timer. La routine SynchCritSection_2 tenta di reimpostare il dispositivo solo se l'operazione di I/O corrente è scaduta, che viene indicata quando il contatore del timer passa a zero. E solo se un tentativo di reimpostazione del dispositivo non è già riuscito, la routine SynchCritSection_2 restituisce FALSE alla routine IoTimer .

Di conseguenza, sia la routine IoTimer precedente che il relativo helper SynchCritSection_2 routine richiedono molto poco tempo per l'esecuzione in circostanze normali. Usando una routine IoTimer in questo modo, un driver di dispositivo garantisce che ogni richiesta di I/O del dispositivo valida possa essere ritentata, se necessario e che una routine CustomDpc non riuscirà a eseguire un IRP solo se un errore hardware non verificabile impedisce che l'IRP venga soddisfatto. Inoltre, il driver fornisce questa funzionalità a un costo molto minimo nel tempo di esecuzione.

La semplicità dello scenario precedente dipende da un dispositivo che esegue una sola operazione alla volta e da un driver che normalmente non si sovrappone alle operazioni di I/O. Un driver che esegue operazioni di I/O del dispositivo sovrapposte o un driver di livello superiore che usa una routine IoTimer per timeout un set di runtime di integrazione allocati dal driver inviati a più di una catena di driver inferiori, avrebbe scenari di timeout più complessi da gestire.