Partilhar via


Usando objetos timer

A figura a seguir ilustra o uso de um temporizador de notificação para configurar um intervalo de tempo limite para uma operação e aguardar enquanto outras rotinas de driver processam uma solicitação de E/S.

diagrama ilustrando a espera de um objeto de temporizador.

Como mostra a figura anterior, um driver deve fornecer armazenamento para o objeto de temporizador, que deve ser inicializado por uma chamada para KeInitializeTimer com um ponteiro para esse armazenamento. Um driver normalmente faz essa chamada de sua rotina AddDevice .

Dentro do contexto de um thread específico, como um thread criado pelo driver ou um thread que solicita uma operação de E/S síncrona, o driver pode aguardar seu objeto de temporizador, conforme mostrado na figura anterior:

  1. O thread chama KeSetTimer com um ponteiro para o objeto de temporizador e um determinado valor DueTime , expresso em unidades de 100 nanossegundos. Um valor positivo para DueTime especifica um tempo absoluto no qual o objeto de temporizador deve ser removido da fila do temporizador do kernel e definido como o estado Sinalizado. Um valor negativo para DueTime especifica um intervalo relativo à hora atual do sistema.

    Observe que o thread (ou a rotina do driver em execução em um thread do sistema) passa um ponteiro NULL para o objeto DPC (mostrado anteriormente na figura que ilustra o uso de objetos de temporizador e DPC para uma rotina CustomTimerDpc) quando ele chama KeSetTimer se ele aguarda o objeto de temporizador em vez de enfileirar uma rotina CustomTimerDpc .

  2. O thread chama KeWaitForSingleObject com um ponteiro para o objeto de temporizador, o que coloca o thread em um estado de espera enquanto o objeto de temporizador está na fila do temporizador do kernel.

  3. O DueTime especificado expira.

  4. O kernel desativa o objeto de temporizador, define-o como o estado Sinalizado e altera o estado do thread de aguardando para pronto.

  5. O kernel despacha o thread para execução assim que um processador está disponível: ou seja, nenhum outro thread com prioridade mais alta está atualmente no estado pronto e não há rotinas de modo kernel a serem executadas em um IRQL mais alto.

As rotinas de driver executadas em IRQL >= DISPATCH_LEVEL podem cronometrar solicitações usando um objeto de temporizador com um objeto DPC associado para enfileirar uma rotina CustomTimerDpc fornecida pelo driver. Somente as rotinas de driver executadas em um contexto de thread não secundário podem aguardar um intervalo diferente de zero em um objeto de temporizador, conforme mostrado na figura anterior.

Como todos os outros threads, um thread criado pelo driver é representado por um objeto de thread de kernel, que também é um objeto dispatcher. Consequentemente, um driver não precisa que seu thread criado pelo driver use um objeto de temporizador para se colocar voluntariamente em um estado de espera para um determinado intervalo. Em vez disso, o thread pode chamar KeDelayExecutionThread com um intervalo fornecido pelo chamador. Para obter mais informações sobre essa técnica, consulte Sondando um dispositivo.

As rotinas DriverEntry, Reinitialize e Unload também são executadas em um contexto de thread do sistema, para que os drivers possam chamar KeWaitForSingleObject com um objeto de temporizador inicializado pelo driver ou KeDelayExecutionThread enquanto estão inicializando ou descarregando. Um driver de dispositivo pode chamar KeStallExecutionProcessor por um intervalo muito curto (preferencialmente algo inferior a 50 microssegundos) se precisar esperar que o dispositivo atualize o estado durante sua inicialização.

No entanto, os drivers de nível superior geralmente usam outro mecanismo de sincronização em suas rotinas DriverEntry e Reinitialize em vez de usar um objeto de temporizador. Drivers de nível superior sempre devem ser projetados para se colocarem em camadas sobre qualquer driver de nível inferior de um determinado tipo ou tipos de dispositivo. Portanto, um driver de nível superior tende a ficar lento para carregar se aguardar em um objeto de temporizador ou chamar KeDelayExecutionThread porque esse driver deve aguardar um intervalo longo o suficiente para acomodar o dispositivo mais lento possível que dá suporte a ele. Observe também que um intervalo "seguro", mas mínimo para tal espera, é muito difícil de determinar.

Da mesma forma, os drivers PnP não devem esperar que outras ações ocorram, mas devem usar o mecanismo de notificação do gerenciador PnP.