Condividi tramite


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 a driver inferiori usando IoCallDriver.

Quando chiama IoSetCompletionRoutine, la routine dispatch specifica le circostanze in cui il gestore 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 errore (InvokeOnError) o annulla IRP (InvokeOnCancel), in qualsiasi combinazione.

Lo scopo di una routine IoCompletion è monitorare le operazioni eseguite dai driver di livello inferiore con 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 disporre degli IRP 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 che un driver di livello inferiore ha completato con un errore

    I driver di livello più elevato, 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 a livelli sopra un driver di porta strettamente accoppiato. Tuttavia, qualsiasi driver intermedio usa routine IoCompletion per ritentare le richieste.

Mentre una routine DispatchReadWrite di livello più alto o intermedio del driver è molto probabile che elabori gli IRP che richiedono una routine IoCompletion, qualsiasi routine di spedizione 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 venga restituito un IRP con STATUS_CANCELLED, per garantire che la routine IoCompletion libera ogni IRP allocato dal driver o controlli lo stato di completamento di ogni riutilizzo di un IRP.

Una routine di dispatch che alloca gli IRP per i driver inferiori nel stack usando IoAllocateIrp o IoBuildAsynchronousFsdRequest deve impostare una routine IoCompletion per ogni IRP allocato dal driver.

  • La routine dispatch deve configurare lo stato riguardo all'IRP originale e ai relativi IRP allocati per l'uso della routine IoCompletion. Come minimo, la routine IoCompletion richiede l'accesso all'IRP originale e un conteggio del numero di IRP aggiuntivi allocati.

  • La procedura di dispatch deve chiamare IoSetCompletionRoutine con tutti i parametri InvokeOnXxx impostati su TRUE per gli IRP allocati.

Una routine dispatch che riutilizza gli IRP per una sequenza di operazioni o che ritenta l'operazione di I/O deve chiamare IoSetCompletionRoutine per ciascun IRP che verrà riutilizzato o ritentato.

  • 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 che la routine IoCompletion deve 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 di invio di qualsiasi driver intermedio deve chiamare IoMarkIrpPending per l'IRP originale. Deve quindi restituire STATUS_PENDING dopo aver inviato l'IRP ai driver inferiori.