Compartilhar via


Pontos a serem considerados ao cancelar IRPs

Esta seção discute as diretrizes para implementar uma rotina cancelar e lidar com IRPs canceláveis. Para obter mais informações sobre como lidar com IRPs canceláveis, consulte o Fluxo de Controle para Enfileiramento de IRPs Cancel-Safe.

Diretrizes gerais para todas as rotinas de cancelamento

O gerente de E/S mantém o bloqueio de rotação de cancelamento sempre que chama a rotina de Cancelamento de um driver. Consequentemente, cada rotina de cancelamento deve:

  • Chame IoReleaseCancelSpinLock antes de retornar o controle.

  • Não chame IoAcquireCancelSpinLock , a menos que ele chame IoReleaseCancelSpinLock primeiro.

  • Faça uma chamada recíproca para IoReleaseCancelSpinLock para cada chamada feita para IoAcquireCancelSpinLock.

Sempre que a rotina Cancel chamar IoReleaseCancelSpinLock, ela deverá passar o IRQL retornado pela chamada mais recente para IoAcquireCancelSpinLock. Ao liberar o bloqueio de rotação adquirido pelo gerente de E/S (e mantido quando a rotina Cancelar foi chamada), a rotina Cancelar deve passar Irp-CancelIrql>.

Um driver não deve chamar rotinas externas (como IoCompleteRequest) enquanto mantém um spin lock, pois isso pode resultar em um deadlock.

Usando a fila definida pelo Gerenciador de E/S

A menos que um driver gerencie suas próprias filas internas de IRPs, sua rotina Cancel é chamada com um IRP de entrada que pode ser um dos seguintes:

  • O CurrentIrp no objeto de dispositivo de alvo de entrada

  • Uma entrada na fila do dispositivo associada ao objeto de destino do dispositivo

A menos que um driver gerencie suas próprias filas internas de IRPs, sua rotina Cancel deve chamar KeRemoveEntryDeviceQueue com o IRP de entrada para verificar se ele é uma entrada na fila de dispositivos associada ao objeto de dispositivo de destino. A rotina Cancel do driver não pode chamar KeRemoveDeviceQueue ou KeRemoveByKeyDeviceQueue porque a rotina não pode assumir que o IRP especificado esteja em qualquer posição determinada na fila de dispositivos.

Estado atual do IRP de entrada

Se uma rotina Cancelar for chamada com um IRP para o qual o driver já iniciou o processamento de E/S e a solicitação será concluída em breve, a rotina Cancelar deverá liberar o spinlock de cancelamento do sistema e retornar o controle.

Se o estado atual do IRP de entrada estiver pendente, uma rotina Cancel deverá fazer o seguinte:

  1. Defina o bloco de status de E/S do IRP de entrada com STATUS_CANCELLED para Status e zero para Informação.

  2. Libere todos os bloqueios de rotação que ele está mantendo, incluindo o bloqueio de rotação de cancelamento do sistema.

  3. Chame IoCompleteRequest com o IRP especificado.

Mantendo IRPs em um estado cancelável

Qualquer rotina de driver que contenha um IRP em um estado cancelável deve chamar IoMarkIrpPending e deve chamar IoSetCancelRoutine para definir seu ponto de entrada para a rotina Cancelar no IRP. Só então essa rotina de driver pode chamar rotinas de suporte adicionais, como IoStartPacket, IoAllocateController ou uma rotina ExInterlockedInsert..List.

Qualquer rotina de driver que processe posteriormente IRPs canceláveis deve verificar se um IRP já foi cancelado antes de iniciar as operações para atender à solicitação. A rotina deve chamar IoSetCancelRoutine para redefinir seu ponto de entrada para a rotina Cancelar para NULL no IRP. Só então essa rotina pode iniciar seu processamento de E/S para o IRP de entrada.

Uma rotina pode ter que redefinir o ponto de entrada para uma rotina Cancel em um IRP se ela, também, passar IRPs para processamento adicional por outras rotinas de driver e esses IRPs possam ser mantidos em um estado cancelável.

Qualquer driver de nível superior que contenha um IRP em um estado cancelável deve redefinir seu ponto de entrada Cancelar para NULL antes de passar o IRP para o driver inferior seguinte com IoCallDriver.

Cancelando um IRP

Qualquer driver de nível superior pode chamar IoCancelIrp com um IRP que foi alocado por ele e passado para processamento posterior por drivers de nível inferior. No entanto, esse driver não pode assumir que o IRP especificado será concluído com STATUS_CANCELLED pelos drivers de nível inferior.

Sincronização

Um driver pode (ou deve, dependendo de seu design) manter informações de estado adicionais em sua extensão de dispositivo para acompanhar o status cancelável de IRPs. Se esse estado for compartilhado por rotinas de driver em execução em IRQL <= DISPATCH_LEVEL, os dados compartilhados deverão ser protegidos com um bloqueio de rotação alocado pelo driver e inicializado.

O driver deve gerenciar cuidadosamente suas aquisições e liberações do spin lock de cancelamento do sistema e seus próprios spin locks. Ele deve conter o bloqueio de rotação de cancelamento do sistema para os intervalos mais curtos possíveis. Antes de acessar um IRP cancelável, esse driver sempre deve verificar o valor retornado de IoSetCancelRoutine para determinar se a rotina Cancelar já está em execução (ou está prestes a ser executada); em caso afirmativo, ele deve permitir que a rotina Cancelar conclua o IRP.

Se um driver de dispositivo mantiver informações de estado sobre IRPs canceláveis que várias rotinas de driver compartilham com seu ISR, essas outras rotinas deverão sincronizar o acesso ao estado compartilhado com o ISR. Somente uma rotina SynchCritSection fornecida pelo driver pode acessar informações de estado que são compartilhadas com o ISR de maneira segura para vários processadores.

Para obter mais informações, consulte Técnicas de Sincronização.