Compartilhar via


Registrando uma rotina IoCompletion

Para registrar uma rotina IoCompletion , uma rotina de expedição chama IoSetCompletionRoutine, fornecendo o endereço da rotina IoCompletion e o IRP que ele passará posteriormente para drivers inferiores usando IoCallDriver.

Quando chama IoSetCompletionRoutine, a rotina de expedição especifica as circunstâncias em que o gerente de E/S deve chamar a rotina de IoCompletion especificada. Você pode optar por ter a rotina IoCompletion chamada se um driver de nível inferior concluir o IRP com êxito (InvokeOnSuccess), concluir o IRP com um erro status valor (InvokeOnError) ou cancelar o IRP (InvokeOnCancel), em qualquer combinação.

A finalidade de uma rotina IoCompletion é monitorar o que os drivers de nível inferior fizeram com o IRP e fazer processamento de conclusão adicional, se necessário. Especificamente, os usos mais comuns para rotinas IoCompletion de um driver são os seguintes:

  • Para descartar um IRP alocado pelo driver com IoAllocateIrp ou IoBuildAsynchronousFsdRequest

    Qualquer driver de nível superior que aloca um IRP usando qualquer uma dessas rotinas de suporte deve fornecer uma rotina IoCompletion para esse IRP. A rotina IoCompletion deve chamar IoFreeIrp para descartar IRPs alocados pelo driver.

  • Para reutilizar um IRP de entrada para solicitar que drivers inferiores concluam alguns números de operações, como transferências parciais, até que a solicitação original possa ser atendida e concluída pela rotina IoCompletion

  • Para repetir uma solicitação que um driver inferior concluiu com um erro

    Drivers de nível mais alto, como sistemas de arquivos, são mais propensos a ter rotinas IoCompletion que tentam repetir solicitações do que drivers intermediários, exceto possivelmente drivers de classe em camadas acima de um driver de porta estreitamente acoplado. No entanto, qualquer driver intermediário usa rotinas IoCompletion para repetir solicitações.

Embora a rotina DispatchReadWrite de um driver intermediário ou de alto nível seja mais provável para processar IRPs que exigem uma rotina IoCompletion , qualquer rotina de expedição em qualquer driver que passe IRPs para drivers inferiores pode registrar uma rotina IoCompletion .

Para IRPs alocados por driver e IRPs reutilizados, a rotina de expedição deve chamar IoSetCompletionRoutine com os seguintes parâmetros boolianos:

  • InvokeOnSuccess definido como TRUE

  • InvokeOnError definido como TRUE

  • InvokeOnCancel definido como TRUE se qualquer driver inferior na cadeia pode lidar com IRPs canceláveis

    Normalmente, InvokeOnCancel é definido como TRUE, independentemente de um IRP ser retornado com STATUS_CANCELLED, para garantir que a rotina IoCompletion libere cada IRP alocado pelo driver ou verifique o status de conclusão de cada reutilização de um IRP.

Uma rotina de expedição que aloca IRPs para drivers inferiores usando IoAllocateIrp ou IoBuildAsynchronousFsdRequestdeve definir uma rotina IoCompletion para cada IRP alocado pelo driver.

  • A rotina de expedição deve configurar o estado sobre o IRP original e seus IRP(s) alocados para a rotina IoCompletion a ser usada. No mínimo, a rotina IoCompletion precisa de acesso ao IRP original e uma contagem de quantos IRPs adicionais foram alocados.

  • A rotina de expedição deve chamar IoSetCompletionRoutine com todos os parâmetros InvokeOnXxx definidos como TRUE para os IRP(s) alocados.

Uma rotina de expedição que reutiliza IRPs para uma sequência de operações ou que repita a operação de E/S deve chamar IoSetCompletionRoutine para cada IRP que será reutilizado ou repetido.

  • A rotina de expedição deve salvar as informações de estado do IRP original para uso subsequente pela rotina IoCompletion .

    Por exemplo, uma rotina DispatchReadWrite deve salvar os parâmetros de transferência relevantes de um IRP de entrada para a rotina IoCompletion antes de configurar uma transferência parcial para o driver mais baixo nesse IRP. Salvar os parâmetros é particularmente importante se a rotina DispatchReadWrite modificar todos os parâmetros que a rotina IoCompletion precisa determinar quando a solicitação original foi atendida.

  • Se a rotina IoCompletion puder repetir a solicitação, a rotina de expedição deverá configurar um limite superior determinado pelo driver para o número de repetições que sua rotina IoCompletion deve tentar antes de concluir o IRP original com um erro.

  • Se um IRP for reutilizado, a rotina de expedição deverá chamar IoSetCompletionRoutine com todos os parâmetros InvokeOnXxx definidos como TRUE.

  • Para uma solicitação assíncrona, a rotina de expedição de qualquer driver intermediário deve chamar IoMarkIrpPending para o IRP original. Em seguida, ele deve retornar STATUS_PENDING depois de enviar o IRP para drivers inferiores.