Compartilhar via


Exemplos de sincronização

Os exemplos a seguir ilustram o que um minidriver precisa fazer em relação à sincronização e inclui exemplos de quando a sincronização não deve ser usada:

  • Exemplo um: minidriver com um ISR em funcionamento

    Se a sincronização de classe de fluxo estiver ativada, todos os pontos de entrada do minidriver serão chamados no IRQL elevado, usando KeSynchronizeExecution, o que significa que o nível de IRQ do adaptador e todos os níveis de IRQ inferiores são mascarados quando o minidriver está executando seu código. Portanto, é imperativo que o minidriver faça apenas uma pequena quantidade de trabalho nesse modo.

    O minidriver não deve executar código que normalmente leva mais do que 10 a 20 microssegundos em um IRQL elevado. Se você usar a compilação de depuração de stream.sys, a classe de stream registrará o tempo gasto no IRQL elevado e verificará se o driver está passando muito tempo lá. Se o minidriver precisar simplesmente programar registros de DMA de hardware para uma solicitação, ou apenas precisar ler portas em seu ISR, geralmente é aceitável realizar todo o processamento em um IRQL elevado.

    Se o minidriver precisar fazer um processamento que leve mais de alguns microssegundos, como um minidriver que transfere dados por meio do PIO, o minidriver deverá usar StreamClassCallAtNewPriority para agendar um retorno de chamada DISPATCH_LEVEL. No retorno de chamada, o minidriver pode levar até cerca de 1/2 a 1 milissegundo para realizar seu processamento. Uma coisa que se deve lembrar quando estiver nesse modo é que o retorno de chamada DISPATCH_LEVEL não é sincronizado com o ISR.

    Essa falta de sincronização não será um problema se o hardware permanecer estável quando o minidriver acessar recursos (por exemplo, portas ou uma fila) durante o retorno de chamada, bem como no ISR. Mas se a instabilidade puder ser um problema, o minidriver deverá usar StreamClassCallAtNewPriority para agendar um callback de alta prioridade, no qual o callback DISPATCH_LEVEL acesse os recursos que são compartilhados com os recursos usados pelo ISR.

    Observe que um retorno de chamada de prioridade ALTA é equivalente a chamar KeSynchronizeExecution. KeSynchronizeExecution requer que o minidriver faça referência a vários parâmetros que StreamClassCallAtNewPriority não faz, mas, em geral, os dois resultam no mesmo comportamento.

    Se o minidriver precisar apenas ocasionalmente executar um código que leve mais de 1/2 a 1 milissegundo ou ocasionalmente precisar chamar serviços em PASSIVE_LEVEL (como no momento da inicialização), a configuração de StreamClassCallAtNewPriority como LOW priority poderá ser usada para adquirir um thread de trabalho PASSIVE_LEVEL. Observe que um retorno de chamada de baixa prioridade não é sincronizado com nada e que o minidriver pode receber novas solicitações (supondo que o parâmetro ReadyForNextRequest NotificationType esteja pendente) ou uma chamada ISR ao executar um retorno de chamada de baixa prioridade.

  • Exemplo dois: minidriver sem um ISR

    Se a sincronização da classe de streaming estiver ativada, os pontos de entrada do minidriver serão todos chamados em DISPATCH_LEVEL. O minidriver pode realizar o processamento de até 1/2 a 1 milissegundo de duração sem a necessidade de ajustar a prioridade. Se o minidriver precisar apenas ocasionalmente executar um código que leve mais de 1/2 milissegundos ou ocasionalmente precisar chamar serviços em PASSIVE_LEVEL (como no momento da inicialização), o StreamClassCallAtNewPriority com prioridade LOW poderá ser usado para adquirir um thread de trabalho PASSIVE_LEVEL. Observe que um retorno de chamada de baixa prioridade não é sincronizado com nada e o minidriver pode receber novas solicitações (supondo que o parâmetro ReadyForNextRequest NotificationType esteja pendente) ao executar um retorno de chamada de baixa prioridade.

  • Quando a sincronização da classe Streamnãodeve ser usada

    Veja a seguir exemplos de situações em que a sincronização de classes de fluxo não deve ser usada. Elas incluem:

    • Quando os drivers frequentemente (mais de 20% das solicitações que o minidriver recebe) precisam fazer o processamento que leva mais de 1 milissegundo, ou precisam chamar frequentemente serviços em PASSIVE_LEVEL, como os serviços do Microsoft DirectDraw. Ao usar a versão de depuração do stream.sys, a classe de fluxo afirmará ambos os casos e interromperá se forem detectados com a sincronização ativada.

    • Quando o minidriver é um filtro sem hardware associado. Esse minidriver deve ser executado em PASSIVE_LEVEL porque não há hardware subjacente para sincronizar e o minidriver normalmente faz muito processamento. Nesse caso, é mais fácil fazer sua própria sincronização do que desperdiçar sobrecarga usando a sincronização de classe de fluxo. Se necessário, use mutexes para proteger suas filas.

      Bugs no código de sincronização geralmente podem ser difíceis de encontrar e, em determinados ambientes (como sistemas operacionais baseados em NT em execução em sistemas multiprocessadores), os bugs podem aparecer somente após muitas horas de estresse. Com base na experiência com fornecedores, esses não são os tipos de coisas que a maioria dos fornecedores tem a capacidade ou o desejo de depurar. Somente os desenvolvedores de drivers familiarizados com o desenvolvimento de drivers de dispositivo WDM totalmente assíncronos devem cuidar de sua própria sincronização.

    • Quando o minidriver é um driver do tipo barramento sobre barramento (por exemplo, um driver periférico USB ou 1394) que não se preocupa com a sincronização do hardware real, mas apenas faz chamadas de solicitações para a próxima camada em PASSIVE_LEVEL e normalmente recebe retornos de chamada em DISPATCH_LEVEL.