Usando itens de trabalho da estrutura
Um item de trabalho é uma tarefa que um driver executa em uma função de retorno de chamada de evento EvtWorkItem . Essas funções são executadas de forma assíncrona, em IRQL = PASSIVE_LEVEL, no contexto de um thread de trabalho do sistema.
Os drivers baseados em estrutura geralmente usam itens de trabalho se uma função EvtInterruptDpc ou EvtDpcFunc , que é executada em IRQL = DISPATCH_LEVEL, deve executar processamento adicional em IRQL = PASSIVE_LEVEL.
Em outras palavras, um driver pode usar itens de trabalho se uma função executada em IRQL = DISPATCH_LEVEL deve chamar uma função que só pode ser chamada em IRQL = PASSIVE_LEVEL.
Normalmente, a função de retorno de chamada EvtInterruptDpc ou EvtDpcFunc de um driver cria um objeto de item de trabalho e o adiciona à fila de itens de trabalho do sistema. Posteriormente, um thread de trabalho do sistema desativa o objeto e chama a função de retorno de chamada EvtWorkItem do item de trabalho.
Drivers de exemplo que usam itens de trabalho
Os drivers baseados em estrutura de exemplo que usam itens de trabalho incluem 1394, AMCC5933, PCIDRV e Toaster.
Configurando um item de trabalho
Para configurar um item de trabalho, o driver deve:
Crie o item de trabalho.
Seu driver chama WdfWorkItemCreate para criar um objeto de item de trabalho e identificar uma função de retorno de chamada EvtWorkItem que processará o item de trabalho.
Armazene informações sobre o item de trabalho.
Normalmente, os drivers usam a memória de contexto do objeto de item de trabalho para armazenar informações sobre a tarefa que a função de retorno de chamada EvtWorkItem deve executar. Quando a função de retorno de chamada EvtWorkItem é chamada, ela pode recuperar as informações acessando essa memória de contexto. Para obter informações sobre como alocar e acessar a memória de contexto, consulte Espaço de Contexto do Objeto framework.
Adicione o item de trabalho à fila de itens de trabalho do sistema.
Seu driver chama WdfWorkItemEnqueue, que adiciona o item de trabalho do driver à fila de itens de trabalho.
Quando o driver chama WdfWorkItemCreate, ele deve fornecer um identificador para um objeto de dispositivo de estrutura ou um objeto de fila de estrutura. Quando o sistema exclui esse objeto, ele também exclui todos os itens de trabalho existentes associados ao objeto . O objeto de item de trabalho será descartado e seu retorno de chamada de item de trabalho associado será limpo antes que o retorno de chamada EvtCleanupCallback do objeto pai seja invocado.
Para obter mais informações sobre as regras de limpeza de uma hierarquia de objetos de estrutura, consulte Ciclo de Vida do Objeto framework.
Usando a função de retorno de chamada Work-Item
Depois que o item de trabalho tiver sido adicionado à fila do item de trabalho, ele permanecerá na fila até que um thread de trabalho do sistema fique disponível. O thread de trabalho do sistema remove o item de trabalho da fila e, em seguida, chama a função de retorno de chamada EvtWorkItem do driver, passando o objeto de item de trabalho como entrada.
Normalmente, a função de retorno de chamada EvtWorkItem executa as seguintes etapas:
Obtém informações fornecidas pelo driver sobre o item de trabalho acessando a memória de contexto do objeto de item de trabalho.
Executa a tarefa especificada. Se necessário, a função de retorno de chamada pode chamar WdfWorkItemGetParentObject para determinar o objeto pai do item de trabalho.
Chama WdfObjectDelete para excluir o objeto de item de trabalho ou, se o driver enviar novamente o item de trabalho, indica que o identificador para o item de trabalho agora está disponível para reutilização.
A tarefa executada pela função de retorno de chamada de cada item de trabalho deve ser relativamente curta. O sistema operacional fornece um número limitado de threads de trabalho do sistema, para que o driver possa impedir o desempenho do sistema se ele usar funções de retorno de chamada de item de trabalho para executar tarefas demoradas.
Criando e excluindo itens de trabalho
Os drivers podem usar uma das duas técnicas a seguir para criar e excluir itens de trabalho:
Use cada item de trabalho uma vez: crie o item de trabalho quando precisar dele e exclua-o imediatamente após ele ser usado.
Essa técnica é útil para drivers que exigem uso pouco frequente (menos de uma vez por minuto) de um pequeno número de itens de trabalho.
Por exemplo, a função de retorno de chamada EvtInterruptDpc de um driver pode chamar WdfWorkItemCreate e, em seguida, WdfWorkItemEnqueue, e a função de retorno de chamada EvtWorkItem do item de trabalho pode chamar WdfObjectDelete.
Se o driver seguir esse cenário e sua função de retorno de chamada EvtInterruptDpc receber uma STATUS_INSUFFICIENT_RESOURCES valor retornado de WdfWorkItemCreate, o driver deverá ser capaz de adiar o trabalho necessário até que os recursos do sistema (normalmente memória) fiquem disponíveis.
Crie um ou mais itens de trabalho que o driver requeira conforme necessário.
Essa técnica é útil para drivers que usam itens de trabalho com frequência (com mais frequência do que uma vez por minuto) ou se a função de retorno de chamada EvtInterruptDpc do driver não pode lidar facilmente com um valor de retorno STATUS_INSUFFICIENT_RESOURCES de WdfWorkItemCreate.
O sistema não aloca um thread de trabalho para um item de trabalho até que o driver chame WdfWorkItemEnqueue. Portanto, mesmo que os threads de trabalho do sistema sejam um recurso limitado, a criação de itens de trabalho ao inicializar um dispositivo consome uma pequena quantidade de memória, mas não afeta de outra forma o desempenho do sistema.
As etapas a seguir descrevem um cenário possível:
- A função de retorno de chamada EvtDriverDeviceAdd de um driver chama WdfWorkItemCreate para obter um identificador de item de trabalho.
- A função de retorno de chamada EvtInterruptDpc do driver cria uma lista de ações que a função de retorno de chamada EvtWorkItem deve executar e, em seguida, chama WdfWorkItemEnqueue, usando o identificador da etapa 1.
- A função de retorno de chamada EvtWorkItem do driver executa a lista de ações e define um sinalizador para indicar que a função de retorno de chamada foi executada.
Posteriormente, cada vez que a função de retorno de chamada EvtInterruptDpc do driver for chamada, ela deverá determinar se a função de retorno de chamada EvtWorkItem foi executada. Se a função de retorno de chamada EvtWorkItem não tiver sido executada, a função de retorno de chamada EvtInterruptDpc não chamará WdfWorkItemEnqueue, pois o item de trabalho ainda está na fila. Nesse caso, a função de retorno de chamada EvtInterruptDpc atualiza apenas a lista de ações para a função de retorno de chamada EvtWorkItem .
Cada item de trabalho está associado a um dispositivo ou uma fila. Quando o dispositivo ou fila associado é removido, a estrutura exclui todos os itens de trabalho associados, portanto, se você estiver usando essa técnica, o driver não precisará chamar WdfObjectDelete.
Alguns drivers podem precisar chamar WdfWorkItemFlush para liberar seus itens de trabalho da fila de itens de trabalho. Para obter um exemplo de uso de WdfWorkItemFlush, consulte a página de referência do método.
Se o driver chamar WdfObjectDelete em um item de trabalho pendente, o resultado dependerá do estado do item de trabalho:
Estado do item de trabalho | Result |
---|---|
Criado, mas não enfileirado | O item de trabalho é limpo imediatamente. |
Enfileirado | Chamar wdfObjectDelete aguarda até que o item de trabalho termine a execução e, em seguida, o item de trabalho seja limpo |
Executando | Se o driver chamar WdfObjectDelete de dentro de EvtWorkItem (no mesmo thread), WdfObjectDelete retornará imediatamente. Depois que EvtWorkItem for concluído, o item de trabalho será limpo. Caso contrário, WdfObjectDelete aguarda a conclusão de EvtWorkItem. |