Partilhar via


Pontos a considerar 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 IRP Cancel-Safe.

Diretrizes gerais para todas as rotinas de cancelamento

O gestor de E/S mantém o spin lock de cancelamento sempre que chama a rotina Cancelar de um driver. Consequentemente, toda rotina de Cancelamento deve:

  • Chame IoReleaseCancelSpinLock antes de devolver o controle.

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

  • Faça uma chamada recíproca para IoReleaseCancelSpinLock para cada chamada que ele faz para IoAcquireCancelSpinLock.

Cada vez que a rotina Cancel chama IoReleaseCancelSpinLock, ela deve 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 bloqueio de rotação porque pode resultar num 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 destino de entrada

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

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 testar se é 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 não pode assumir que o IRP dado está em qualquer posição específica na fila do dispositivo.

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 sistema cancelar bloqueio de rotação e controle de retorno.

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

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

  2. Solte todos os bloqueios de rotação que estiver a manter, incluindo o bloqueio de rotação do sistema de cancelamento.

  3. Chame IoCompleteRequest com o IRP fornecido.

Manter IRPs num estado cancelável

Qualquer rotina de driver que mantenha um IRP em um estado cancelável deve chamar IoMarkIrpPending e deve chamar IoSetCancelRoutine para definir seu ponto de entrada para a rotina Cancel 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 posteriormente processe IRPs canceláveis deve verificar se um IRP já foi cancelado antes de iniciar as operações para satisfazer a solicitação. A rotina deve chamar IoSetCancelRoutine para redefinir seu ponto de entrada para a rotina Cancel para NULL no IRP. Só então essa rotina pode começar seu processamento de E/S para o IRP de entrada.

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

Qualquer driver de nível superior que mantenha um IRP em um estado cancelável deve redefinir seu ponto de entrada Cancel para NULL antes de passar o IRP para o próximo driver inferior com IoCallDriver.

Cancelar um IRP

Qualquer driver de nível superior pode chamar IoCancelIrp com um IRP que ele alocou e passou para processamento adicional por drivers de nível inferior. No entanto, tal driver não pode presumir que o IRP dado será completado com STATUS_CANCELLED por drivers inferiores.

Sincronização

Um driver pode (ou deve, dependendo do seu projeto) manter informações adicionais de estado na sua extensão de dispositivo para seguir o estado cancelável dos IRPs. Se este estado for partilhado por rotinas de driver executadas em IRQL <= DISPATCH_LEVEL, os dados partilhados deverão ser protegidos com um spin lock alocado e inicializado pelo driver.

O driver deve gerir cuidadosamente suas aquisições e liberações do bloqueio de rotação de cancelamento do sistema e de seus próprios bloqueios de rotação. Ele deve segurar o sistema cancelar bloqueio de rotação para os intervalos mais curtos possíveis. Antes de acessar um IRP cancelável, esse driver deve sempre verificar o valor de retorno de IoSetCancelRoutine para determinar se a rotina Cancel já está em execução (ou está prestes a ser executada); em caso afirmativo, deve deixar a rotina Cancelar concluir o IRP.

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

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