Partilhar via


Exemplos de sincronização

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

  • Exemplo um: Minidriver com um ISR funcional

    Se a sincronização da classe de fluxo de dados estiver ativada, todos os pontos de entrada do minidriver sã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 mais baixos são mascarados quando o minidriver está executando o seu código. Portanto, é imperativo que o minidriver faça apenas uma pequena quantidade de trabalho neste modo.

    O minidriver não deve executar código que normalmente leva mais de 10 a 20 microssegundos no IRQL elevado. Se utilizar a compilação de depuração do stream.sys, a classe de fluxo regista a quantidade de tempo gasto no nível elevado de IRQL e verifica se o driver está a gastar demasiado tempo lá. Se o minidriver simplesmente precisa programar os registos DMA do hardware para uma solicitação, ou apenas precisa ler portas no seu ISR, geralmente é aceitável fazer todo o processamento no IRQL elevado.

    Se o minidriver precisar fazer um processamento que leva mais do que alguns microssegundos, como um minidriver que transfere dados através do PIO, o minidriver deve 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 fazer seu processamento. Uma coisa a lembrar ao utilizar este modo é que o callback DISPATCH_LEVEL não está sincronizado com o ISR.

    Essa falta de sincronização não é um problema se o hardware permanecer estável quando o minidriver acessa recursos (por exemplo, portas ou uma fila) durante o retorno de chamada, bem como no ISR. Mas se a instabilidade poderia ser um problema, o minidriver deve usar StreamClassCallAtNewPriority para agendar um retorno de chamada de prioridade alta onde o retorno de chamada DISPATCH_LEVEL acede a recursos que são partilhados com os recursos usados pelo ISR.

    Observe que um callback 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 só ocasionalmente precisar executar código que leva mais de 1/2 a 1 milissegundo, ou ocasionalmente precisar chamar serviços em PASSIVE_LEVEL (como no momento da inicialização), definir StreamClassCallAtNewPriority como prioridade BAIXA pode ser usado para adquirir um thread de trabalho PASSIVE_LEVEL. Observe que um retorno de chamada de baixa prioridade não está 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 ISR

    Se a sincronização de classes de fluxo estiver ativada, os pontos de entrada do minidriver serão todos chamados em DISPATCH_LEVEL. O minidriver pode fazer processamento de até cerca de 1/2 a 1 milissegundo de duração sem a necessidade de ajustar a prioridade. Se o minidriver só ocasionalmente precisa executar código que leva mais de 1/2 milissegundo, ou ocasionalmente precisa chamar serviços em PASSIVE_LEVEL (como no momento da inicialização), então StreamClassCallAtNewPriority com prioridade BAIXA pode 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 de classe de streamnão deveser usada

    A seguir estão exemplos de situações em que a sincronização de classe de fluxo não deve ser usada. Estes são, entre outros:

    • Quando os drivers frequentemente (mais de cerca de 20% das solicitações que o minidriver recebe) precisam realizar um processamento que leva mais de 1 milissegundo ou precisam frequentemente chamar serviços em nível PASSIVE_LEVEL, tais como os serviços Microsoft DirectDraw. Ao usar a versão de depuração do stream.sys, a classe de fluxo verificará ambos os casos e parará se forem detetados com a sincronização ativada.

    • Quando o minidriver é um filtro sem hardware associado. Esse minidriver deve estar sendo executado em PASSIVE_LEVEL uma vez que não há hardware subjacente para sincronizar e o minidriver normalmente faz muito processamento. Neste 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 as filas.

      Bugs no código de sincronização muitas vezes podem ser difíceis de encontrar, e em certos ambientes (como sistemas operacionais baseados em NT executados em sistemas multiprocessadores) bugs podem aparecer apenas 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 tentar fazer a sua própria sincronização.

    • Quando o minidriver é um driver do tipo bus-on-bus (por exemplo, um driver periférico USB ou 1394) que não precisa preocupar-se com a sincronização do hardware real, mas apenas faz chamadas de solicitações para a próxima camada no PASSIVE_LEVEL e recebe callbacks geralmente no DISPATCH_LEVEL.