Esempi di utilizzo di code di I/O

Per ogni dispositivo connesso a un sistema e supportato da un determinato driver, il driver può usare le combinazioni seguenti di code di I/O e gestori di richieste:

  • Una singola coda di I/O predefinita e un singolo gestore di richieste EvtIoDefault. Il framework fornirà tutte le richieste del dispositivo alla coda predefinita e chiamerà il gestore EvtIoDefault del driver per recapitare ogni richiesta al driver.

  • Una singola coda di I/O predefinita e più gestori di richieste, ad esempio EvtIoRead, EvtIoWrite e EvtIoDeviceControl. Il framework fornirà tutte le richieste del dispositivo alla coda predefinita. Chiamerà il gestore EvtIoRead del driver per recapitare le richieste di lettura, il gestore EvtIoWrite per recapitare le richieste di scrittura e il gestore EvtIoDeviceControl per recapitare le richieste di controllo di I/O del dispositivo.

  • Più code di I/O, ad esempio una per le richieste di lettura e un'altra per le richieste di scrittura. Per ogni coda, il driver fornisce un solo gestore di richieste perché la coda riceve un solo tipo di richiesta.

  • Più code di I/O, ognuna con più gestori di richieste.

Di seguito sono riportati alcuni scenari di esempio:

Una singola coda di I/O sequenziale

Se si scrive un driver di funzione per un'unità disco in grado di gestire solo le richieste di lettura e scrittura una alla volta, il driver di funzione necessita di una sola coda di I/O per ogni dispositivo.

Il driver può usare la coda di I/O predefinita creata dal framework quando il driver chiama WdfIoQueueCreate e imposta DefaultQueue su TRUE nella struttura WDF_IO_QUEUE_CONFIG della coda. Nella struttura WDF_IO_QUEUE_CONFIG, il driver deve anche specificare:

  • WdfIoQueueDispatchSequential come metodo di invio, quindi la coda di I/O predefinita recapita le richieste di I/O al driver in modo sincrono.

  • Una singola funzione di callback di eventi , EvtIoDefault, che riceverà tutte le richieste di I/O.

Ogni volta che una richiesta di I/O è disponibile nella coda di I/O predefinita del driver, il framework recapita la richiesta al driver chiamando il gestore di richieste EvtIoDefault del driver. Se nella coda diventa disponibile un'altra richiesta, il framework non lo recapita finché il driver non chiama WdfRequestComplete per la richiesta recapitata in precedenza.

Più code di I/O sequenziali e una coda manuale

Si consideri un dispositivo porta seriale con le caratteristiche seguenti:

  • Può eseguire contemporaneamente un'operazione di lettura e un'operazione di scrittura.

  • Non può eseguire più operazioni di lettura o scrittura in modo asincrono.

  • Può ricevere richieste di controllo di I/O del dispositivo per informazioni sullo stato. Il driver del dispositivo potrebbe richiedere molto tempo per completare alcune di queste richieste, ad esempio una richiesta di attesa per una modifica dello stato.

Un driver di funzione per questo dispositivo può usare più code di I/O sequenziali per dispositivo. Il driver chiamerebbe WdfIoQueueCrea tre volte: una volta per creare una coda predefinita e due volte per creare due code di I/O aggiuntive. Nella struttura WDF_IO_QUEUE_CONFIG per ognuna di queste code, il driver deve specificare:

  • WdfIoQueueDispatchSequential come metodo di invio per ogni coda, in modo che il framework invii le richieste di I/O al driver in modo sincrono.

  • Gestore di richieste diverso per ogni coda (EvtIoDefault, EvtIoRead e EvtIoWrite), che riceverà le richieste di I/O della coda.

Dopo aver chiamato WdfIoQueueCreate, il driver potrebbe chiamare WdfDeviceConfigureRequestDispatching due volte: per inoltrare tutte le richieste di lettura a una delle code aggiuntive e a tutte le richieste di scrittura all'altra.

Con questa configurazione, la funzione di callback EvtIoDefault della coda di I/O predefinita del dispositivo riceverà solo le richieste di controllo di I/O del dispositivo per le informazioni sullo stato.

Se il driver deve contenere una richiesta di stato per molto tempo, può creare una quarta coda e specificare WdfIoQueueDispatchManual come metodo di invio. Quando il driver riceve una richiesta di informazioni che deve attendere, può inserire la richiesta in questa coda aggiuntiva fino a quando le informazioni sullo stato non diventano disponibili. Il driver può quindi recuperare la richiesta dalla coda e completarla. Nel frattempo, la coda predefinita può recapitare un'altra richiesta al driver.

Una singola coda di I/O parallela

I controller del disco IDE possono sovrapporsi ad alcune operazioni di I/O, ma non ad altre. Ad esempio, mentre un controller elabora un'operazione di lettura o scrittura su un disco, può inviare un comando seek a un altro disco. D'altra parte, più comandi di lettura e scrittura simultanei non sono supportati.

Un driver di funzione per questo controller deve esaminare ogni richiesta di I/O. Se il driver riceve un comando seek, deve determinare se il comando seek può essere elaborato. Il comando seek non può essere elaborato se:

  • L'unità disco specificata è già occupata.

  • È in corso la formattazione di un'unità disco e pertanto nessun'altra unità può essere attiva.

Per ogni dispositivo connesso al controller, il driver potrebbe chiamare WdfIoQueueCreate per creare una coda di I/O predefinita. Nella struttura WDF_IO_QUEUE_CONFIG per ognuna di queste code, il driver deve specificare:

  • WdfIoQueueDispatchParallel come metodo di invio per ogni coda, in modo che il framework invii le richieste di I/O al driver in modo asincrono.

  • Funzione di callback di eventi EvtIoDefault per ogni coda, che riceverà le richieste di I/O della coda.

Con questa configurazione, a ogni dispositivo viene assegnata una coda di I/O parallela. Il driver deve esaminare ogni richiesta di I/O che il framework distribuisce da ogni coda di I/O. Se il driver può elaborare immediatamente la richiesta, lo fa. In caso contrario, il driver chiama WdfIoQueueStop, che impedisce al framework di recapitare le richieste fino a quando il driver chiama WdfIoQueueStart.

Più code di I/O parallele

Una scheda host SCSI è un esempio di dispositivo che supporta operazioni di I/O asincrone sovrapposte. Fino a 32 dispositivi possono essere connessi alla scheda. Si consideri un sistema con la configurazione seguente:

  • Alcuni dei dispositivi connessi alla scheda SCSI supportano la "riselezione" e alcuni non lo supportano. Se un dispositivo SCSI supporta la riselezione, durante un'operazione di I/O il dispositivo può rilasciare temporaneamente la scheda in modo che la scheda possa gestire un altro dispositivo. Il primo dispositivo successivamente si riseleziona per completare l'operazione.

  • La scheda SCSI usa cassette postali hardware per passare richieste e risposte tra il driver e i dispositivi. Se un dispositivo è pronto per una richiesta ma non sono disponibili cassette postali, il dispositivo deve attendere.

Per ottenere prestazioni ottimali, il driver di funzione per questa scheda host SCSI deve ricevere richieste di I/O dal framework non appena sono disponibili. Il driver deve esaminare ogni richiesta e determinare se può essere avviato immediatamente o deve essere posticipato fino a quando il dispositivo e le risorse (ad esempio la memoria della cassetta postale) sono disponibili.

È probabile che il driver usi più code di I/O parallele. Per ogni dispositivo connesso alla scheda, il driver chiamerebbe WdfIoQueueCreate per creare una coda di I/O predefinita. Nella struttura WDF_IO_QUEUE_CONFIG per ognuna di queste code, il driver deve specificare:

  • WdfIoQueueDispatchParallel come metodo di invio per ogni coda, in modo che il framework invii le richieste di I/O al driver in modo asincrono.

  • Funzione di callback di eventi EvtIoDefault per ogni coda, che riceverà le richieste di I/O della coda.

Ogni funzione di callback EvtIoDefault di ogni coda di I/O deve esaminare le richieste di I/O della coda, man mano che vengono recapitate, e determinare se ognuna può essere eseguita immediatamente. Se il dispositivo e le risorse di sistema sono disponibili, il driver avvia l'operazione di I/O. Se il dispositivo o le risorse non sono disponibili, il driver deve chiamare WdfIoQueueStop per interrompere il recapito di richieste aggiuntive fino a quando non è possibile elaborare quello corrente.

Facoltativamente, il driver può chiamare WdfIoQueueCreate per creare code aggiuntive per ogni dispositivo. Il driver può quindi chiamare WdfRequestForwardToIoQueue per accodare nuovamente alcuni tipi di richieste alle code aggiuntive. Quando il framework recapita richieste da una coda aggiuntiva, il driver può chiamare WdfIoQueueStop, se necessario, in tale coda anziché nella coda predefinita, riducendo al minimo il numero o il tipo di richieste per cui il recapito viene posticipato.