Diretrizes para escrever rotinas de DPC
Tenha em mente os seguintes pontos ao escrever uma rotina DpcForIsr ou CustomDpc :
Uma rotina DpcForIsr ou CustomDpc deve sincronizar seu acesso a um dispositivo físico e a quaisquer informações de estado ou recursos compartilhados que o driver mantém, com outras rotinas do driver que acessam os mesmos locais de memória ou dispositivo.
Se uma rotina DpcForIsr ou CustomDpc compartilhar o dispositivo ou o estado com um ISR, ele deverá chamar KeSynchronizeExecution, fornecendo o endereço de uma rotina SynchCritSection fornecida pelo driver que programa o dispositivo ou acessa o estado compartilhado. Para obter mais informações, consulte Usando seções críticas.
Se uma rotina DpcForIsr ou CustomDpc compartilhar o estado ou os recursos, como uma fila interconectada ou um objeto de temporizador, com rotinas diferentes de um ISR, ele deverá proteger o estado compartilhado ou os recursos com um bloqueio de rotação executivo inicializado pelo driver. Para obter mais informações, consulte Spin Locks.
As rotinas DpcForIsr e CustomDpc são executadas em IRQL = DISPATCH_LEVEL, o que restringe o conjunto de rotinas de suporte que podem chamar.
Por exemplo, as rotinas DpcForIsr e CustomDpc não podem acessar nem alocar memória paginável e não podem esperar que os objetos do dispatcher do kernel sejam definidos para o estado sinalizado. Por outro lado, eles podem adquirir e liberar o bloqueio de rotação executivo de um driver com KeAcquireSpinLockAtDpcLevel e KeReleaseSpinLockFromDpcLevel, que são executados mais rápido que KeAcquireSpinLock e KeReleaseSpinLock.
Embora uma rotina de DPC não possa fazer chamadas de bloqueio, ela pode enfileirar um item de trabalho para ser executado em um thread de trabalho do sistema executado em IRQL igual a PASSIVE_LEVEL. O item de trabalho pode fazer chamadas de bloqueio que esperam em objetos dispatcher. Para enfileirar um item de trabalho, uma rotina DpcForIsr normalmente chama uma rotina como IoQueueWorkItem e uma rotina CustomDpc normalmente chama a rotina ExQueueWorkItem .
As rotinas DpcForIsr e CustomDpc normalmente são responsáveis por iniciar a próxima operação de E/S no dispositivo.
Para drivers de dispositivo físico de nível mais baixo que usam E/S direta, essa responsabilidade pode incluir o uso de uma rotina SynchCritSection para programar o dispositivo para transferir mais dados para satisfazer o IRP atual antes que o driver chame IoStartNextPacket.
As rotinas DpcForIsr e CustomDpc devem ser executadas apenas por breves períodos e devem delegar o máximo de processamento possível para threads de trabalho.
Enquanto uma rotina DPC é executada em um processador, todos os threads são impedidos de serem executados no mesmo processador. Outras rotinas de DPC enfileiradas e prontas para execução podem ser impedidas de serem executadas até que a rotina atual do DPC seja concluída. Para evitar degradar a capacidade de resposta do sistema, uma rotina DPC típica deve ser executada para não mais de 100 microssegundos cada vez que for chamada. Se uma tarefa exigir mais de 100 microssegundos e precisar ser executada em IRQL igual a DISPATCH_LEVEL, a rotina DPC deverá terminar após 100 microssegundos e agendar uma ou mais rotinas CustomTimerDpc para concluir a tarefa posteriormente. Para obter mais informações sobre rotinas CustomTimerDpc , consulte Objetos do Temporizador e DPCs.
Uma rotina DPC deve executar apenas tarefas que devem ser executadas em DISPATCH_LEVEL e, em seguida, delegar qualquer trabalho relacionado à interrupção restante para threads executados em IRQL = PASSIVE_LEVEL. Por exemplo, uma rotina de DPC pode enfileirar um item de trabalho para ser executado em um thread de trabalho do sistema.
As rotinas de DPC que chamam a rotina KeStallExecutionProcessor para atrasar a execução não devem especificar atrasos de mais de 100 microssegundos.
Use as ferramentas de análise de desempenho no WDK para avaliar os tempos de execução das rotinas de DPC. Para obter um exemplo que usa a ferramenta Tracelog para monitorar os tempos de execução de DPC, consulte Exemplo 15: Medindo o tempo de DPC/ISR.
Se o driver usa DMA e sua rotina AdapterControl retorna KeepObject ou DeallocateObjectKeepRegisters (mantendo assim o canal do controlador de DMA do sistema ou o adaptador de master de barramento para operações de transferência adicionais), a rotina DpcForIsr ou CustomDpc é responsável por liberar o objeto adaptador ou registros de mapa com FreeAdapterChannel ou FreeMapRegisters antes de concluir o IRP atual e retornar o controle.
Se um driver de dispositivo físico de nível mais baixo configurar um objeto de controlador para sincronizar operações de E/S por meio do controlador para dispositivos anexados, sua rotina DpcForIsr ou CustomDpc será responsável por liberar o objeto controlador usando IoFreeController antes de concluir o IRP atual e retornar o controle.
As rotinas DpcForIsr e CustomDpc são geralmente responsáveis por registrar em log quaisquer erros de dispositivo ocorridos durante o processamento de uma determinada solicitação, repetir a solicitação atual, se necessário e possível, e por definir o bloco de E/S status e chamar IoCompleteRequest para o IRP atual.
Se o driver e o dispositivo derem suporte a operações de E/S sobrepostas, o driver deverá seguir as regras para lidar com operações de E/S sobrepostas.
A rotina DpcForIsr ou CustomDpc de qualquer driver geralmente conclui o processamento de E/S somente para um subconjunto dos códigos de controle de E/S públicos aos quais o driver deve dar suporte. Em particular, a rotina DPC conclui operações para solicitações de controle de dispositivo com as seguintes características:
Solicitações que alteram o estado do dispositivo físico
Solicitações que exigem o retorno de informações inerentemente voláteis sobre o dispositivo físico