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 Cancel-Safe Enfileiramento IRP.
Diretrizes gerais para todas as rotinas de cancelamento
O gerenciador de E/S mantém o bloqueio de rotação de cancelamento sempre que chama a rotina Cancelar de um driver. Consequentemente, cada rotina Cancelar 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 Cancelar 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 bloqueio de rotação porque um deadlock pode resultar.
Usando a fila definida pelo gerenciador de E/S
A menos que um driver gerencie suas próprias filas internas de IRPs, sua rotina Cancelar é 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 Cancelar deve chamar KeRemoveEntryDeviceQueue com o IRP de entrada para testar se ele é uma entrada na fila de dispositivos associada ao objeto de dispositivo de destino. A rotina Cancelar do driver não pode chamar KeRemoveDeviceQueue ou KeRemoveByKeyDeviceQueue porque não pode assumir que o IRP especificado 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 bloqueio de rotação de cancelamento do sistema e retornar o controle.
Se o estado atual do IRP de entrada estiver Pendente, uma rotina Cancelar deverá fazer o seguinte:
Defina o bloco de status de E/S do IRP de entrada com STATUS_CANCELLED para Status e zero para Informações.
Libere os bloqueios de rotação que ele está mantendo, incluindo o bloqueio de rotação de cancelamento do sistema.
Chame IoCompleteRequest com o IRP fornecido.
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. Somente então essa rotina de driver pode chamar rotinas de suporte adicionais, como IoStartPacket, IoAllocateController ou exInterlockedInsert.. Rotina de lista.
Qualquer rotina de driver que processe posteriormente IRPs canceláveis deve marcar se um IRP já foi cancelado antes de iniciar 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. Somente 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 Cancelar em um IRP se, também, passar IRPs para processamento adicional por outras rotinas de driver e esses IRPs podem 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 alocado e passado para processamento adicional por drivers de nível inferior. No entanto, esse driver não pode assumir que o IRP fornecido será concluído com STATUS_CANCELLED por drivers inferiores.
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 suas aquisições e versões do sistema cancelam o bloqueio de rotação e seus próprios bloqueios de rotação cuidadosamente. 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 deve sempre marcar o valor retornado de IoSetCancelRoutine para determinar se a rotina Cancelar já está em execução (ou está prestes a ser executada); nesse caso, 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 compartilhadas com o ISR de maneira segura para vários processadores.
Para obter mais informações, consulte Técnicas de sincronização.