Puntos a tener en cuenta al cancelar IRP
En esta sección se describen las instrucciones para implementar una rutina Cancel y controlar los IRP cancelables. Para obtener más información sobre el control de IRP cancelables, consulte El flujo de control para Cancel-Safe IRP Queuing.
Directrices generales para todas las rutinas de cancelación
El administrador de E/S contiene el bloqueo de giro de cancelación cada vez que llama a la rutina Cancel de un controlador. Por lo tanto, todas las rutinas Cancel deben:
Llame a IoReleaseCancelSpinLock antes de que devuelva el control.
No llame a IoAcquireCancelSpinLock a menos que llame primero a IoReleaseCancelSpinLock .
Realice una llamada recíproca a IoReleaseCancelSpinLock para cada llamada que realiza a IoAcquireCancelSpinLock.
Cada vez que la rutina Cancel llama a IoReleaseCancelSpinLock, debe pasar el IRQL devuelto por la llamada más reciente a IoAcquireCancelSpinLock. Al liberar el bloqueo de número adquirido por el administrador de E/S (y se mantiene cuando se llamó a la rutina Cancel), la rutina Cancel debe pasar Irp-CancelIrql>.
Un controlador no debe llamar a rutinas externas (como IoCompleteRequest) mientras mantiene un bloqueo de número porque puede producirse un interbloqueo.
Uso de la cola definida por el Administrador de E/S
A menos que un controlador administre sus propias colas internas de IRP, se llama a su rutina Cancel con un IRP entrante que podría ser cualquiera de los siguientes:
CurrentIrp en el objeto de dispositivo de destino de entrada
Entrada en la cola de dispositivos asociada al objeto de dispositivo de destino
A menos que un controlador administre sus propias colas internas de IRP, su rutina Cancel debe llamar a KeRemoveEntryDeviceQueue con el IRP de entrada para probar si es una entrada en la cola de dispositivos asociada al objeto de dispositivo de destino. La rutina Cancel del controlador no puede llamar a KeRemoveDeviceQueue o KeRemoveByKeyDeviceQueue porque no puede suponer que el IRP especificado está en una posición determinada de la cola del dispositivo.
Estado actual del IRP de entrada
Si se llama a una rutina Cancel con un IRP para el que el controlador ya ha iniciado el procesamiento de E/S y la solicitud se completará pronto, la rutina Cancel debe liberar el bloqueo de número de cancelación del sistema y el control de retorno.
Si el estado actual del IRP de entrada es Pendiente, una rutina Cancel debe hacer lo siguiente:
Establezca el bloque de estado de E/S de IRP de entrada con STATUS_CANCELLED para Estado y cero para Información.
Libere los bloqueos de giro que contiene, incluido el bloqueo de giro de cancelación del sistema.
Llame a IoCompleteRequest con el IRP especificado.
Mantener los IRP en un estado cancelable
Cualquier rutina de controlador que contenga un IRP en un estado cancelable debe llamar a IoMarkIrpPending y debe llamar a IoSetCancelRoutine para establecer su punto de entrada para la rutina Cancel en irP. Solo entonces puede esa rutina de controlador llamar a rutinas de soporte técnico adicionales, como IoStartPacket, IoAllocateController o exInterlockedInsert.. Rutina de lista .
Cualquier rutina de controlador que procese posteriormente irP cancelables debe comprobar si ya se ha cancelado un IRP antes de que comience las operaciones para satisfacer la solicitud. La rutina debe llamar a IoSetCancelRoutine para restablecer su punto de entrada para la rutina Cancel a NULL en IRP. Solo entonces puede esa rutina iniciar su procesamiento de E/S para el IRP de entrada.
Es posible que una rutina tenga que restablecer el punto de entrada de una rutina Cancel en un IRP si también pasa IRP para su posterior procesamiento por otras rutinas de controlador y esos IRP se pueden mantener en un estado cancelable.
Cualquier controlador de nivel superior que contenga un IRP en un estado cancelable debe restablecer su punto de entrada Cancel a NULL antes de pasar el IRP al controlador inferior siguiente con IoCallDriver.
Cancelación de un IRP
Cualquier controlador de nivel superior puede llamar a IoCancelIrp con un IRP que haya asignado y pasado para su posterior procesamiento mediante controladores de nivel inferior. Sin embargo, este controlador no puede suponer que el IRP especificado se completará con STATUS_CANCELLED por controladores inferiores.
Synchronization
Un controlador puede (o debe, dependiendo de su diseño) mantener información de estado adicional en su extensión de dispositivo para realizar un seguimiento del estado cancelable de los IRP. Si las rutinas de controlador que se ejecutan en IRQL <= DISPATCH_LEVEL comparten este estado, los datos compartidos deben protegerse con un bloqueo de número asignado por el controlador e inicializado.
El controlador debe administrar sus adquisiciones y lanzamientos del bloqueo de giro de cancelación del sistema y sus propios bloqueos de giro cuidadosamente. Debe contener el bloqueo de giro de cancelación del sistema para los intervalos más cortos posibles. Antes de acceder a un IRP cancelable, este controlador siempre debe comprobar el valor devuelto de IoSetCancelRoutine para determinar si la rutina Cancel ya se está ejecutando (o está a punto de ejecutarse); Si es así, debería permitir que la rutina Cancel complete el IRP.
Si un controlador de dispositivo mantiene información de estado sobre los IRP cancelables que varias rutinas de controlador comparten con su ISR, estas otras rutinas deben sincronizar el acceso al estado compartido con el ISR. Solo una rutina SynchCritSection proporcionada por el controlador puede acceder a la información de estado que se comparte con el ISR de forma segura para varios procesadores.
Para obtener más información, vea Técnicas de sincronización.