Gestione delle code dei dispositivi

In genere, la gestione I/O (ad eccezione degli FSD) crea un oggetto coda del dispositivo associato quando un driver chiama IoCreateDevice. Fornisce anche IoStartPacket e IoStartNextPacket, che i driver possono chiamare per avere i provider di servizi di gestione I/O inserire i provider di servizi di integrazione nella coda del dispositivo associata o chiamare le routine StartIo.

Di conseguenza, è raramente necessario (o particolarmente utile) per un driver configurare i propri oggetti code di dispositivi per i gruppi di integrazione. È probabile che i candidati siano driver, ad esempio il driver di porta SCSI, che devono coordinare i irP in ingresso da un certo numero di driver di classe strettamente associati per dispositivi eterogenei che vengono gestiti tramite un singolo controller o adattatore del bus.

In altre parole, un driver per un controller array di dischi è più probabile che usi un oggetto controller creato dal driver rispetto alla configurazione di oggetti coda di dispositivi supplementari, mentre un driver per un adattatore del bus aggiuntivo e di un set di driver di classe è leggermente più probabile usare code di dispositivi supplementari.

Uso di code di dispositivi supplementari con una routine StartIo

Chiamando IoStartPacket e IoStartNextPacket, le routine Dispatch e DpcForIsr (o CustomDpc) di un driver sincronizzano le chiamate alla routine StartIo usando la coda del dispositivo creata dal driver quando il driver ha creato l'oggetto dispositivo. Per un driver di porta con una routine StartIo, IoStartPacket e IoStartNextPacket inserire e rimuovere i provider di integrazione nella coda del dispositivo per il controller/scheda del dispositivo condiviso del driver di porta. Se il driver di porta configura anche code di dispositivi supplementari per contenere le richieste provenienti da driver di classe di livello superiore strettamente abbinati, deve "ordinare" gli IRP in ingresso nelle code di dispositivi supplementari, in genere nella routine StartIo .

Il driver di porta deve determinare quale coda di dispositivo supplementare ogni IRP appartiene prima di provare a inserire tale IRP nella coda appropriata. Un puntatore all'oggetto dispositivo di destinazione viene passato con l'IRP alla routine Dispatch del driver. Il driver deve salvare il puntatore per l'uso in "ordinamento" dei irP in ingresso. Si noti che il puntatore dell'oggetto dispositivo passato alla routine StartIo è il proprio oggetto dispositivo del driver, che rappresenta il controller del dispositivo/adattatore, quindi non può essere usato per questo scopo.

Dopo aver accodato tutti gli indirizzi IP, il driver programma il controller/l'adattatore condiviso per eseguire la richiesta. Pertanto, il driver di porta può elaborare le richieste in ingresso per tutti i dispositivi in un primo momento, primo servizio fino a quando una chiamata a KeInsertDeviceQueue inserisce un'IRP in una determinata coda di dispositivi del driver di classe.

Usando la propria coda di dispositivi per l'elaborazione di tutti gli IP tramite la routine StartIo , il driver di porta sottostante serializza le operazioni tramite il controller/adattatore del dispositivo condiviso (o bus) a tutti i dispositivi collegati. In alcuni casi, l'uso di IRP per ogni dispositivo supportato in una coda di dispositivi separata, questo driver di porta impedisce l'elaborazione di IP per un dispositivo già occupato mentre aumenta la velocità effettiva di I/O per ogni altro dispositivo che esegue I/O tramite il relativo hardware condiviso.

In risposta alla chiamata a IoStartPacket dalla routine Dispatch del driver di porta, la gestione I/O chiama immediatamente la routine StartIo del driver o inserisce immediatamente l'IRP nella coda del dispositivo associata all'oggetto dispositivo per il controller/adattatore condiviso del driver della porta.

Il driver di porta deve mantenere le proprie informazioni sullo stato su ognuno dei dispositivi eterogenei che servizi tramite il controller/adattatore del dispositivo condiviso.

Tenere presente quanto segue durante la progettazione di driver di classe/porta con code di dispositivi supplementari:

  • Un driver non può facilmente ottenere un puntatore a un oggetto dispositivo creato da qualsiasi driver a livelli sopra se stesso, ad eccezione dell'oggetto dispositivo nella parte superiore dello stack di dispositivi.

    Per progettazione, il gestore di I/O non fornisce una routine di supporto per ottenere un puntatore di questo tipo. Inoltre, l'ordine in cui vengono caricati i driver rende impossibile che i driver inferiori ottengano puntatori per gli oggetti dispositivo di livello superiore, che non sono ancora stati creati quando un driver di livello inferiore aggiunge il dispositivo.

    Anche se IoGetAttachedDeviceReference restituisce un puntatore all'oggetto dispositivo di livello più alto nello stack di un driver, un driver deve usare questo puntatore solo per designare una destinazione per le richieste di I/O nello stack. Un driver non deve tentare di leggere o scrivere l'oggetto dispositivo.

  • Un driver non può usare un puntatore a un oggetto dispositivo creato da qualsiasi driver livelli sopra se stesso, ad eccezione dell'invio di richieste all'inizio dello stack di dispositivi.

    Non è possibile sincronizzare l'accesso a un singolo oggetto dispositivo (e l'estensione del dispositivo) tra due driver in modo multiprocessore sicuro. Nessuno dei due driver può fare ipotesi sull'elaborazione dell'I/O che sta attualmente eseguendo l'altro driver.

Anche per i driver di classe/porta strettamente associati, ogni driver di classe deve usare il puntatore agli oggetti del dispositivo del driver di porta solo per passare irPs usando IoCallDriver. Il driver di porta sottostante deve mantenere il proprio stato, probabilmente nell'estensione del dispositivo del driver di porta, sulle richieste che elabora per i dispositivi di classe strettamente associati.

Gestione di code di dispositivi supplementari tra routine driver

Qualsiasi driver di porta che accoda IRP nelle code di dispositivi supplementari per un set strettamente abbinato di driver di classe deve gestire in modo efficiente la situazione seguente:

  1. Le routine Dispatch hanno inserito irP per un dispositivo specifico nella coda del dispositivo creata dal driver per tale dispositivo.

  2. Gli IRP per altri dispositivi continuano a venire in coda, per essere accodati alla routine StartIo del driver con IoStartPacket e da elaborare tramite il controller di dispositivo condiviso.

  3. Il controller del dispositivo non diventa inattivo, ma ogni IRP mantenuto nella coda del dispositivo creata dal driver deve anche essere accodato alla routine StartIo del driver il prima possibile.

Di conseguenza, la routine DpcForIsr del driver di porta deve tentare di trasferire un'IRP dalla coda del dispositivo interno del driver per un determinato dispositivo nella coda del dispositivo per l'adattatore/controller condiviso ogni volta che il driver di porta completa un'IRP, come indicato di seguito:

  1. La routine DpcForIsr chiama IoStartNextPacket per avere la routine StartIo iniziare a elaborare il successivo IRP accodato al controller del dispositivo condiviso.

  2. La routine DpcForIsr chiama KeRemoveDeviceQueue per dequeue il successivo IRP (se presente) che tiene nella coda interna del dispositivo per il dispositivo per conto del quale sta per completare un IRP.

  3. Se KeRemoveDeviceQueue restituisce un puntatore non NULL, la routine DpcForIsr chiama IoStartPacket con l'IRP appena dequeued per averlo accodato al controller/scheda del dispositivo condiviso. In caso contrario, la chiamata a KeRemoveDeviceQueue reimposta semplicemente lo stato dell'oggetto coda del dispositivo su Not-Busy e la routine DpcForIsr omette la chiamata a IoStartPacket.

  4. La routine DpcForIsr chiama quindi IoCompleteRequest con l'IRP di input per cui il driver di porta ha appena completato l'elaborazione di I/O, impostando il blocco di stato di I/O con un errore o soddisfando la richiesta di I/O.

Si noti che la sequenza precedente implica che la routine DpcForIsr deve anche determinare il dispositivo per il quale sta completando l'IRP corrente (input) per gestire in modo efficiente l'accodamento interno di IRP.

Se il driver di porta tenta di attendere fino a quando il controller/adattatore condiviso non è inattivo prima di dequeuare gli INDIRIZZI IP contenuti nelle code dei dispositivi supplementari, il driver potrebbe restare leggero per cui c'era una richiesta di I/O pesante mentre ha attivato immediatamente ogni altro dispositivo per cui la richiesta di I/O corrente era effettivamente molto più leggera.