Linee guida per la scrittura di routine DPC
Tenere presente quanto segue quando si scrive una routine DpcForIsr o CustomDpc :
Una routine DpcForIsr o CustomDpc deve sincronizzare l'accesso a un dispositivo fisico e a qualsiasi informazione o risorsa di stato condivisa gestita dal driver, con le altre routine del driver che accedono allo stesso dispositivo o posizioni di memoria.
Se una routine DpcForIsr o CustomDpc condivide il dispositivo o lo stato con un ISR, deve chiamare KeSynchronizeExecution, specificando l'indirizzo di una routine SynchCritSection fornita dal driver che programma il dispositivo o accede allo stato condiviso. Per altre informazioni, vedere Uso di sezioni critiche.
Se una routine DpcForIsr o CustomDpc condivide lo stato o le risorse, ad esempio una coda interlocked o un oggetto timer, con routine diverse da un ISR, deve proteggere lo stato o le risorse condivise con un blocco spin esecutivo inizializzato driver. Per altre informazioni, vedere Blocchi di spin.
Le routine DpcForIsr e CustomDpc vengono eseguite in IRQL = DISPATCH_LEVEL, che limita il set di routine di supporto che possono chiamare.
Ad esempio, le routine DpcForIsr e CustomDpc non possono accedere né allocare memoria impaginabile e non possono attendere che gli oggetti del dispatcher del kernel vengano impostati sullo stato segnalato. D'altra parte, possono acquisire e rilasciare il blocco esecutivo di un driver con KeAcquireSpinLockAtDpcLevel e KeReleaseSpinLockFromDpcLevel, che vengono eseguiti più velocemente di KeAcquireSpinLock e KeReleaseSpinLock.
Anche se una routine DPC non può effettuare chiamate di blocco, può accodare un elemento di lavoro da eseguire in un thread di lavoro di sistema eseguito in IRQL uguale a PASSIVE_LEVEL. L'elemento di lavoro può effettuare chiamate che bloccano l'attesa sugli oggetti dispatcher. Per accodare un elemento di lavoro, una routine DpcForIsr chiama in genere una routine come IoQueueWorkItem e una routine CustomDpc chiama in genere la routine ExQueueWorkItem .
Le routine DpcForIsr e CustomDpc sono in genere responsabili dell'avvio dell'operazione di I/O successiva nel dispositivo.
Per i driver di dispositivo fisici di livello più basso che usano i/O diretti, questa responsabilità può includere l'uso di una routine SynchCritSection per programmare il dispositivo per trasferire più dati per soddisfare l'IRP corrente prima che il driver chiami IoStartNextPacket.
Le routine DpcForIsr e CustomDpc devono essere eseguite solo per brevi periodi e devono delegare il più possibile l'elaborazione ai thread di lavoro.
Mentre una routine DPC viene eseguita su un processore, tutti i thread non vengono eseguiti sullo stesso processore. Altre routine DPC accodate e pronte per l'esecuzione possono essere bloccate fino al termine della routine DPC corrente. Per evitare la velocità di risposta del sistema degradante, una routine DPC tipica deve essere eseguita per non più di 100 microsecondi ogni volta che viene chiamata. Se un'attività richiede più di 100 microsecondi e deve essere eseguita in IRQL uguale a DISPATCH_LEVEL, la routine DPC deve terminare dopo 100 microsecondi e pianificare una o più routine CustomTimerDpc per completare l'attività in un secondo momento. Per altre informazioni sulle routine CustomTimerDpc , vedere Oggetti timer e SCHEDE di dominio.
Una routine DPC deve eseguire solo attività che devono essere eseguite in DISPATCH_LEVEL e quindi delegare qualsiasi lavoro rimanente correlato agli interruzioni che vengono eseguiti in IRQL = PASSIVE_LEVEL. Ad esempio, una routine DPC può accodare un elemento di lavoro da eseguire in un thread di lavoro di sistema.
Le routine DPC che chiamano la routine KeStallExecutionProcessor per ritardare l'esecuzione non devono specificare ritardi di oltre 100 microsecondi.
Usare gli strumenti di analisi delle prestazioni nel WDK per valutare i tempi di esecuzione delle routine DPC. Per un esempio che usa lo strumento Tracelog per monitorare i tempi di esecuzione DPC, vedere Esempio 15: Misurazione del tempo DPC/ISR.
Se il driver usa DMA e la routine AdapterControl restituisce KeepObject oDeallocateObjectKeepRegisters (mantenendo quindi il canale del controller DMA di sistema o l'adattatore master del bus per operazioni di trasferimento aggiuntive), la routine DpcForIsr o CustomDpc è responsabile del rilascio dell'oggetto adapter o dei registri mappa con FreeAdapterChannel o FreeMapRegisters prima di completare il controllo IRP corrente e restituisce il controllo.
Se un driver di dispositivo fisico di livello più basso configura un oggetto controller per sincronizzare le operazioni di I/O tramite il controller ai dispositivi collegati, la routine DpcForIsr o CustomDpc è responsabile del rilascio dell'oggetto controller usando IoFreeController prima di completare l'IRP corrente e restituisce il controllo.
Le routine DpcForIsr e CustomDpc sono in genere responsabili della registrazione di eventuali errori del dispositivo che si sono verificati durante l'elaborazione di una determinata richiesta, ritentando la richiesta corrente se necessario e possibile e per impostare il blocco di stato I/O e chiamando IoCompleteRequest per l'IRP corrente.
Se il driver e il dispositivo supportano operazioni di I/O sovrapposte, il driver deve seguire le regole per gestire le operazioni di I/O sovrapposte.
La routine DpcForIsr o CustomDpc di qualsiasi driver completa in genere l'elaborazione di I/O solo per un subset dei codici di controllo I/O pubblici che il driver deve supportare. In particolare, la routine DPC completa le operazioni per le richieste di controllo del dispositivo con le caratteristiche seguenti:
Richieste che modificano lo stato del dispositivo fisico
Richieste che richiedono la restituzione di informazioni intrinsecamente volatili sul dispositivo fisico