Registrazione di una routine IoCompletion
Per registrare una routine IoCompletion , una routine dispatch chiama IoSetCompletionRoutine, fornendo l'indirizzo della routine IoCompletion e l'IRP che passerà successivamente ai driver inferiori usando IoCallDriver.
Quando chiama IoSetCompletionRoutine, la routine dispatch specifica le circostanze in cui il gestore di I/O deve chiamare la routine IoCompletion specificata. È possibile scegliere di chiamare la routine IoCompletion se un driver di livello inferiore completa correttamente L'IRP (InvokeOnSuccess), completa l'IRP con un valore di stato di errore (InvokeOnError) o annulla LRP (InvokeOnCancel), in qualsiasi combinazione.
Lo scopo di una routine IoCompletion è monitorare le operazioni eseguite dai driver di livello inferiore con L'IRP e per eseguire ulteriori elaborazioni di completamento, se necessario. In particolare, gli usi più comuni per le routine IoCompletion di un driver sono i seguenti:
Per eliminare un IRP allocato dal driver con IoAllocateIrp o IoBuildAsynchronousFsdRequest
Qualsiasi driver di livello superiore che alloca un IRP usando una di queste routine di supporto deve fornire una routine IoCompletion per tale IRP. La routine IoCompletion deve chiamare IoFreeIrp per eliminare i runtime di integrazione allocati dal driver.
Per riutilizzare un IRP in ingresso per richiedere che i driver inferiori completino alcune operazioni, ad esempio trasferimenti parziali, fino a quando la richiesta originale non può essere soddisfatta e completata dalla routine IoCompletion
Per ripetere una richiesta di completamento di un driver inferiore con un errore
I driver di livello più alto, ad esempio i file system, hanno maggiori probabilità di avere routine IoCompletion che tentano di ritentare le richieste rispetto ai driver intermedi, ad eccezione dei driver di classe eventualmente sovrapposti rispetto a un driver di porta strettamente accoppiato. Tuttavia, qualsiasi driver intermedio usa routine IoCompletion per ripetere le richieste.
Anche se è molto probabile che una routine DispatchReadWrite di livello più alto o intermedio elabori i runtime di integrazione che richiedono una routine IoCompletion , qualsiasi routine dispatch in qualsiasi driver che passa irP a driver inferiori può registrare una routine IoCompletion .
Per i runtime di integrazione allocati dal driver e i runtime di integrazione riutilizzati, la routine dispatch deve chiamare IoSetCompletionRoutine con i parametri booleani seguenti:
InvokeOnSuccess impostato su TRUE
InvokeOnError impostato su TRUE
InvokeOnCancel impostato su TRUE se un driver inferiore nella catena potrebbe gestire irP annullabili
In genere , InvokeOnCancel è impostato su TRUE, indipendentemente dal fatto che un IRP venga restituito con STATUS_CANCELLED, per garantire che la routine IoCompletion liberi ogni IRP allocato dal driver o controlli lo stato di completamento di ogni riutilizzo di un IRP.
Una routine dispatch che alloca i provider di integrazione per i driver inferiori usando IoAllocateIrp o IoBuildAsynchronousFsdRequestdeve impostare una routine IoCompletion per ogni IRP allocata dal driver.
La routine dispatch deve impostare lo stato sia sull'IRP originale che sui relativi IRP allocati per la routine IoCompletion da usare. Come minimo, la routine IoCompletion deve accedere all'IRP originale e un conteggio del numero di IRP aggiuntivi allocati.
La routine dispatch deve chiamare IoSetCompletionRoutine con tutti i parametri InvokeOnXxx impostati su TRUE per le operazioni di IRP allocate.
Una routine dispatch che riutilizza i provider di integrazione per una sequenza di operazioni o che ritenta l'operazione di I/O deve chiamare IoSetCompletionRoutine per ogni IRP che verrà riutilizzata o ritentata.
La routine dispatch deve salvare le informazioni sullo stato di IRP originali, per usarle successivamente dalla routine IoCompletion .
Ad esempio, una routine DispatchReadWrite deve salvare i parametri di trasferimento pertinenti di un IRP di input per la routine IoCompletion prima di configurare un trasferimento parziale per il driver inferiore successivo in tale IRP. Il salvataggio dei parametri è particolarmente importante se la routine DispatchReadWrite modifica tutti i parametri necessari alla routine IoCompletion per determinare quando la richiesta originale è stata soddisfatta.
Se la routine IoCompletion può ritentare la richiesta, la routine dispatch deve impostare un limite superiore determinato dal driver per il numero di tentativi della routine IoCompletion prima di completare l'IRP originale con un errore.
Se un IRP deve essere riutilizzato, la routine dispatch deve chiamare IoSetCompletionRoutine con tutti i parametri InvokeOnXxx impostati su TRUE.
Per una richiesta asincrona, la routine dispatch di qualsiasi driver intermedio deve chiamare IoMarkIrpPending per l'IRP originale. Deve quindi restituire STATUS_PENDING dopo l'invio dell'IRP ai driver inferiori.