Compartilhar via


Usando uma rotina IoTimer

Enquanto o temporizador do objeto de dispositivo associado está habilitado, a rotina IoTimer é chamada aproximadamente uma vez por segundo. No entanto, como os intervalos nos quais cada rotina IoTimer é chamada dependem da resolução do relógio do sistema, não suponha que uma rotina IoTimer seja chamada precisamente em um limite de um segundo.

Nota Uma rotina IoTimer , como todas as rotinas DPC, é chamada em IRQL = DISPATCH_LEVEL. Enquanto uma rotina DPC é executada, todos os threads são impedidos de serem executados no mesmo processador. Os desenvolvedores de driver devem projetar cuidadosamente suas rotinas IoTimer para serem executadas o mais breve possível.

Talvez o uso mais comum para uma rotina IoTimer seja o tempo limite das operações de E/S do dispositivo para um IRP. Considere o cenário a seguir para usar uma rotina IoTimer como um temporizador em execução em um driver de dispositivo:

  1. Quando ele inicia o dispositivo, o driver inicializa um contador de temporizador na extensão do dispositivo para -1, indicando que não há operações de E/S do dispositivo atual e chama IoStartTimer pouco antes de retornar STATUS_SUCCESS.

    Sempre que a rotina IoTimer é chamada, ela verifica se o contador de temporizador é -1 e, em caso afirmativo, retorna o controle.

  2. A rotina StartIo do driver inicializa o contador de temporizador na extensão do dispositivo para um limite superior, além de um segundo adicional caso a rotina IoTimer tenha sido executada. Em seguida, ele usa KeSynchronizeExecution para chamar uma rotina de SynchCritSection_1 , que programa o dispositivo físico para a operação solicitada pelo IRP atual.

  3. O ISR do driver redefine o contador de temporizador como -1 antes de enfileirar a rotina DpcForIsr do driver ou uma rotina CustomDpc .

  4. Sempre que a rotina IoTimer é chamada, ela verifica se o contador de temporizador foi redefinido pelo ISR para -1 e, em caso afirmativo, retorna o controle. Caso contrário, a rotina IoTimer usa KeSynchronizeExecution para chamar uma rotina de SynchCritSection_2 , que ajusta o contador de temporizador em algum número determinado pelo driver de segundos.

  5. A rotina SynchCritSection_2 retorna TRUE para a rotina IoTimer , desde que a solicitação atual ainda não tenha esgotado. Se o contador de temporizador for para zero, a rotina SynchCritSection_2 redefinirá o contador de temporizador para um valor de tempo limite de redefinição determinado pelo driver, definirá um sinalizador de redefinição esperado para si mesmo (e para o DpcForIsr) em sua área de contexto, tentará redefinir o dispositivo e retornará TRUE.

    A rotina de SynchCritSection_2 será chamada novamente se sua operação de redefinição também atingir o tempo limite no dispositivo, quando retornar FALSE. Se a redefinição for bem-sucedida, a rotina DpcForIsr determinará que o dispositivo foi redefinido do sinalizador esperado de redefinição e tentará novamente a solicitação, repetindo as ações da rotina StartIo , conforme descrito na Etapa 2.

  6. Se a rotina SynchCritSection_2 retornar FALSE, a rotina IoTimer pressupõe que o dispositivo físico está em um estado desconhecido porque uma tentativa de redefini-lo já falhou. Nessas circunstâncias, a rotina IoTimer enfileira uma rotina CustomDpc e retorna. Essa rotina CustomDpc registra um erro de E/S do dispositivo, chama IoStartNextPacket, falha no IRP atual e retorna.

Se o ISR desse driver de dispositivo redefinir o contador de temporizador compartilhado para -1, conforme descrito na Etapa 3, a rotina DpcForIsr do driver concluirá o processamento de E/S controlado por interrupção do IRP atual. O contador de temporizador de redefinição indica que essa operação de E/S do dispositivo não atingiu o tempo limite, portanto, a rotina IoTimer não precisa alterar o contador de temporizador.

Na maioria das circunstâncias, a rotina SynchCritSection_2 anterior simplesmente diminui o contador de temporizador. A rotina SynchCritSection_2 tentará redefinir o dispositivo somente se a operação de E/S atual tiver ultrapassado o tempo limite, o que é indicado quando o contador de temporizador for para zero. E somente se uma tentativa de redefinir o dispositivo já tiver falhado, a rotina SynchCritSection_2 retornará FALSE para a rotina IoTimer .

Consequentemente, tanto a rotina anterior do IoTimer quanto sua rotina de SynchCritSection_2 auxiliar levam muito pouco tempo para serem executadas em circunstâncias normais. Usando uma rotina IoTimer dessa maneira, um driver de dispositivo garante que cada solicitação de E/S de dispositivo válida possa ser repetida, se necessário, e que uma rotina CustomDpc falhará em um IRP somente se uma falha de hardware não corrigivel impedir que o IRP seja atendido. Além disso, o driver fornece essa funcionalidade a um custo muito pequeno no tempo de execução.

A simplicidade do cenário anterior depende de um dispositivo que faz apenas uma operação por vez e em um driver que normalmente não se sobrepõe às operações de E/S. Um driver que executa operações de E/S de dispositivo sobrepostas ou um driver de nível superior que usa uma rotina IoTimer para atingir um conjunto de IRPs alocados por driver enviados a mais de uma cadeia de drivers inferiores teria cenários de tempo limite mais complexos para gerenciar.