Compartir a través de


Registro de una rutina de IoCompletion

Para registrar una rutina de IoCompletion , una rutina de envío llama a IoSetCompletionRoutine, proporcionando la dirección de la rutina ioCompletion y el IRP que pasará posteriormente a controladores inferiores mediante IoCallDriver.

Cuando llama a IoSetCompletionRoutine, la rutina de envío especifica las circunstancias en las que el administrador de E/S debe llamar a la rutina de IoCompletion especificada. Puede elegir que se llame a la rutina IoCompletion si un controlador de nivel inferior completa el IRP correctamente (InvokeOnSuccess), completa el IRP con un valor de estado de error (InvokeOnError) o cancela el IRP (InvokeOnCancel), en cualquier combinación.

El propósito de una rutina de IoCompletion es supervisar lo que hicieron los controladores de nivel inferior con el IRP y realizar un procesamiento de finalización adicional, si es necesario. En concreto, los usos más comunes para las rutinas de IoCompletion de un controlador son los siguientes:

  • Para eliminar un IRP que el controlador ha asignado con IoAllocateIrp o IoBuildAsynchronousFsdRequest

    Cualquier controlador de nivel superior que asigne un IRP mediante cualquiera de estas rutinas de soporte técnico debe proporcionar una rutina de IoCompletion para ese IRP. La rutina IoCompletion debe llamar a IoFreeIrp para eliminar los IRP asignados por el controlador.

  • Para reutilizar un IRP entrante para solicitar que los controladores inferiores completen cierto número de operaciones, como transferencias parciales, hasta que la rutina ioCompletion pueda satisfacer y completar la solicitud original.

  • Para reintentar una solicitud que un controlador inferior completó con un error

    Los controladores de nivel superior, como los sistemas de archivos, tienen más probabilidades de tener rutinas de IoCompletion que intentan reintentar solicitudes que son controladores intermedios, excepto posiblemente controladores de clase superpuestos por encima de un controlador de puerto estrechamente acoplado. Sin embargo, cualquier controlador intermedio usa rutinas de IoCompletion para reintentar las solicitudes.

Aunque la rutina DispatchReadWrite de un controlador intermedio o de nivel superior es más probable que procese irP que requieran una rutina de IoCompletion , cualquier rutina de envío en cualquier controlador que pase IRP a controladores inferiores puede registrar una rutina de IoCompletion .

En el caso de los IRP asignados por el controlador y los IRP reutilizados, la rutina de distribución debe llamar a IoSetCompletionRoutine con los siguientes parámetros booleanos:

  • InvokeOnSuccess establecido en TRUE

  • InvokeOnError establecido en TRUE

  • InvokeOnCancel se establece en TRUE si algún controlador inferior de la cadena puede controlar irP cancelables.

    Normalmente, InvokeOnCancel se establece en TRUE, independientemente de si se puede devolver un IRP con STATUS_CANCELLED, para asegurarse de que la rutina IoCompletion libera cada IRP asignado por el controlador o comprueba el estado de finalización de cada reutilización de un IRP.

Una rutina de distribución que asigna IRP para controladores inferiores mediante IoAllocateIrp o IoBuildAsynchronousFsdRequestdebe establecer una rutina de IoCompletion para cada IRP asignado por el controlador.

  • La rutina de envío debe configurar el estado sobre el IRP original y sus IRP asignados para que la rutina ioCompletion la use. Como mínimo, la rutina IoCompletion necesita acceso al IRP original y un recuento de cuántos IRP adicionales se asignaron.

  • La rutina de distribución debe llamar a IoSetCompletionRoutine con todos los parámetros InvokeOnXxx establecidos en TRUE para los IRP que asigna.

Una rutina de envío que reutiliza los IRP para una secuencia de operaciones, o que reintenta la operación de E/S, debe llamar a IoSetCompletionRoutine para cada IRP que se volverá a usar o reintentar.

  • La rutina de envío debe guardar la información de estado del IRP original para su uso posterior por la rutina IoCompletion .

    Por ejemplo, una rutina DispatchReadWrite debe guardar los parámetros de transferencia pertinentes de un IRP de entrada para la rutina IoCompletion antes de configurar una transferencia parcial para el controlador inferior siguiente en ese IRP. Guardar los parámetros es especialmente importante si la rutina DispatchReadWrite modifica los parámetros que la rutina IoCompletion necesita determinar cuándo se ha cumplido la solicitud original.

  • Si la rutina IoCompletion puede reintentar la solicitud, la rutina de envío debe configurar un límite superior determinado por el controlador para el número de reintentos que su rutina de IoCompletion debe intentar antes de completar el IRP original con un error.

  • Si se va a reutilizar un IRP, la rutina de envío debe llamar a IoSetCompletionRoutine con todos los parámetros InvokeOnXxx establecidos en TRUE.

  • Para una solicitud asincrónica, la rutina de envío de cualquier controlador intermedio debe llamar a IoMarkIrpPending para el IRP original. A continuación, debe devolver STATUS_PENDING después de enviar el IRP a controladores inferiores.