Administración de colas interbloqueadas con un subproceso de Driver-Created
Los nuevos controladores deben usar el marco de cola irP seguro para cancelar en preferencia a los métodos descritos en esta sección.
Al igual que el controlador del controlador de disquete del sistema, un controlador con un subproceso dedicado al dispositivo, en lugar de una rutina StartIo , normalmente administra su propia puesta en cola de IRP en una cola de interbloqueo doblemente vinculada. El subproceso del controlador extrae los IRP de su cola interbloqueada cuando hay trabajo que realizar en el dispositivo.
En general, el controlador debe administrar la sincronización con su subproceso a los recursos compartidos entre el subproceso y otras rutinas de controlador. El controlador también debe tener alguna manera de notificar a su subproceso creado por el controlador que los IRP están en cola. Normalmente, el subproceso espera en un objeto distribuidor, almacenado en la extensión del dispositivo, hasta que las rutinas dispatch del controlador establecen el objeto dispatcher en el estado Signaled después de insertar un IRP en la cola interbloqueada.
Cuando se llama a las rutinas de distribución del controlador, cada una comprueba los parámetros en la ubicación de la pila de E/S del IRP de entrada y, si son válidos, pone en cola la solicitud para su posterior procesamiento. Para cada IRP en cola en un subproceso dedicado al controlador, la rutina de distribución debe configurar el contexto que su subproceso necesita para procesar ese IRP antes de llamar a ExInterlockedInsertXxxList. La ubicación de la pila de E/S del controlador en cada IRP proporciona al subproceso del controlador acceso a la extensión de dispositivo del dispositivo de destino, donde el controlador puede compartir información de contexto con su subproceso, ya que el subproceso quita cada IRP de la cola.
Un controlador que pone en cola los IRP cancelables debe implementar una rutina Cancelar . Dado que los IRP se cancelan de forma asincrónica, debe asegurarse de que el controlador evita las condiciones de carrera que pueden dar lugar. Consulte Synchronizing IRP Cancellation (Sincronización de la cancelación de IRP ) Para obtener más información sobre las condiciones de carrera asociadas a la cancelación de IRP y técnicas para evitarlas.
Cualquier subproceso creado por el controlador se ejecuta en IRQL = PASSIVE_LEVEL y en una prioridad en tiempo de ejecución base establecida anteriormente cuando el controlador llamado PsCreateSystemThread. La llamada del subproceso a ExInterlockedRemoveHeadList genera temporalmente irQL para DISPATCH_LEVEL en el procesador actual mientras el IRP se quita de la cola interna del controlador. El IRQL original se restaura para PASSIVE_LEVEL de vuelta desde esta llamada.
Cualquier subproceso de controlador (o devolución de llamada de subproceso de trabajo proporcionado por el controlador) debe administrar cuidadosamente las IRQL en las que se ejecuta. Por ejemplo, considere lo siguiente:
Dado que los subprocesos del sistema se ejecutan normalmente en IRQL = PASSIVE_LEVEL, es posible que un subproceso de controlador espere a que los objetos de distribuidor definidos por el kernel se establezcan en el estado señalado.
Por ejemplo, un subproceso dedicado al dispositivo podría esperar a que otros controladores satisfagan un evento y completen algún número de IRP de transferencia parcial que el subproceso configura con IoBuildSynchronousFsdRequest.
Sin embargo, este tipo de subproceso dedicado al dispositivo debe generar IRQL en el procesador actual antes de llamar a determinadas rutinas de soporte técnico.
Por ejemplo, si un controlador usa DMA, su subproceso dedicado al dispositivo debe anidar sus llamadas a AllocateAdapterChannel y FreeAdapterChannel entre las llamadas a KeRaiseIrql y KeLowerIrql porque estas rutinas y otras rutinas de soporte técnico para las operaciones DMA deben llamarse en IRQL = DISPATCH_LEVEL.
Recuerde que las rutinas StartIo se ejecutan en DISPATCH_LEVEL, por lo que los controladores que usan DMA no necesitan realizar llamadas a las rutinas keXxxIrql desde sus rutinas StartIo .
Un subproceso creado por el controlador puede tener acceso a la memoria paginable porque se ejecuta en un contexto de subproceso nobitrario (propio) en IRQL = PASSIVE_LEVEL, pero muchas otras rutinas de controlador estándar se ejecutan en IRQL >= DISPATCH_LEVEL. Si un subproceso creado por el controlador asigna memoria a la que puede acceder dicha rutina, debe asignar la memoria del grupo no paginado. Por ejemplo, si un subproceso dedicado al dispositivo asigna cualquier búfer al que acceda más adelante el ISR o SynchCritSection del controlador, AdapterControl, AdapterListControl, ControllerControl, DpcForIsr, CustomDpc, IoTimer, CustomTimerDpc o, en un controlador de nivel superior, la rutina IoCompletion , la memoria asignada por subprocesos no puede ser paginable.
Si el controlador mantiene información de estado compartido o recursos en una extensión de dispositivo, un subproceso de controlador (como una rutina StartIo ) debe sincronizar su acceso a un dispositivo físico y a los datos compartidos con las demás rutinas del controlador que acceden al mismo dispositivo, ubicación de memoria o recursos.
Si el subproceso comparte el dispositivo o el estado con el ISR, debe usar KeSynchronizeExecution para llamar a una rutina SynchCritSection proporcionada por el controlador para programar el dispositivo o para acceder al estado compartido. Consulte Uso de secciones críticas.
Si el subproceso comparte el estado o los recursos con rutinas distintas del ISR, el controlador debe proteger el estado compartido o los recursos con un bloqueo de número ejecutivo inicializado para el controlador para el que el controlador proporciona el almacenamiento. Para obtener más información, consulte Bloqueos de número.
Para obtener más información sobre los inconvenientes de diseño de un subproceso de controlador para un dispositivo lento, consulte Sondear un dispositivo. Consulte también Administración de prioridades de hardware. Para obtener información específica sobre las IRCL para rutinas de soporte técnico concretas, consulte la página de referencia de la rutina.