Directrices para escribir rutinas DPC
Tenga en cuenta los siguientes puntos al escribir una rutina DpcForIsr o CustomDpc :
Una rutina DpcForIsr o CustomDpc debe sincronizar su acceso a un dispositivo físico y a cualquier información de estado o recursos compartidos que mantenga el controlador, con las demás rutinas del controlador que acceden a las mismas ubicaciones de dispositivo o memoria.
Si una rutina DpcForIsr o CustomDpc comparte el dispositivo o el estado con un ISR, debe llamar a KeSynchronizeExecution, proporcionando la dirección de una rutina SynchCritSection proporcionada por el controlador que programa el dispositivo o accede al estado compartido. Para obtener más información, consulte Uso de secciones críticas.
Si una rutina DpcForIsr o CustomDpc comparte el estado o los recursos, como una cola interbloqueada o un objeto de temporizador, con rutinas distintas de un ISR, debe proteger el estado compartido o los recursos con un bloqueo de giro ejecutivo inicializado por el controlador. Para obtener más información, consulte Bloqueos de número.
Las rutinas DpcForIsr y CustomDpc se ejecutan en IRQL = DISPATCH_LEVEL, lo que restringe el conjunto de rutinas de soporte técnico a las que pueden llamar.
Por ejemplo, las rutinas DpcForIsr y CustomDpc no pueden tener acceso ni asignar memoria paginable, y no pueden esperar a que los objetos de distribuidor del kernel se establezcan en el estado señalado. Por otro lado, pueden adquirir y liberar el bloqueo de giro ejecutivo de un controlador con KeAcquireSpinLockAtDpcLevel y KeReleaseSpinLockFromDpcLevel, que se ejecutan más rápido que KeAcquireSpinLock y KeReleaseSpinLock.
Aunque una rutina DPC no puede realizar llamadas de bloqueo, puede poner en cola un elemento de trabajo para ejecutarse en un subproceso de trabajo del sistema que se ejecuta en IRQL igual a PASSIVE_LEVEL. El elemento de trabajo puede realizar llamadas de bloqueo que esperan en objetos de distribuidor. Para poner en cola un elemento de trabajo, una rutina DpcForIsr normalmente llama a una rutina como IoQueueWorkItem y una rutina CustomDpc normalmente llama a la rutina ExQueueWorkItem .
Las rutinas DpcForIsr y CustomDpc suelen ser responsables de iniciar la siguiente operación de E/S en el dispositivo.
Para los controladores de dispositivos físicos de nivel más bajo que usan E/S directa, esta responsabilidad puede incluir el uso de una rutina SynchCritSection para programar el dispositivo para transferir más datos con el fin de satisfacer el IRP actual antes de que el controlador llame a IoStartNextPacket.
Las rutinas DpcForIsr y CustomDpc solo deben ejecutarse durante breves períodos y deben delegar tanto procesamiento como sea posible para los subprocesos de trabajo.
Mientras una rutina DPC se ejecuta en un procesador, se impide que todos los subprocesos se ejecuten en el mismo procesador. Se puede bloquear la ejecución de otras rutinas DPC que están en cola y listas para ejecutarse hasta que finalice la rutina DPC actual. Para evitar degradar la capacidad de respuesta del sistema, se debe ejecutar una rutina típica de DPC para no más de 100 microsegundos cada vez que se llama. Si una tarea requiere más de 100 microsegundos y debe ejecutarse en IRQL igual a DISPATCH_LEVEL, la rutina DPC debe finalizar después de 100 microsegundos y programar una o varias rutinas CustomTimerDpc para completar la tarea más adelante. Para obtener más información sobre las rutinas CustomTimerDpc , vea Objetos de temporizador y DPC.
Una rutina DPC solo debe realizar tareas que se deben ejecutar en DISPATCH_LEVEL y, a continuación, delegar cualquier trabajo relacionado con interrupciones restante en subprocesos que se ejecutan en IRQL = PASSIVE_LEVEL. Por ejemplo, una rutina DPC puede poner en cola un elemento de trabajo para ejecutarse en un subproceso de trabajo del sistema.
Las rutinas DPC que llaman a la rutina KeStallExecutionProcessor para retrasar la ejecución no deben especificar retrasos de más de 100 microsegundos.
Use las herramientas de análisis de rendimiento del WDK para evaluar los tiempos de ejecución de las rutinas de DPC. Para ver un ejemplo que usa la herramienta Tracelog para supervisar los tiempos de ejecución de DPC, vea Ejemplo 15: Medición del tiempo de DPC/ISR.
Si el controlador usa DMA y su rutina AdapterControl devuelve KeepObject o DeallocateObjectKeepRegisters (conservando así el canal del controlador DMA del sistema o el adaptador de bus-master para operaciones de transferencia adicionales), la rutina DpcForIsr o CustomDpc es responsable de liberar el objeto de adaptador o los registros de mapa con FreeAdapterChannel o FreeMapRegisters antes de completar el IRP actual y devuelve el control.
Si un controlador de dispositivo físico de nivel más bajo configura un objeto de controlador para sincronizar las operaciones de E/S a través del controlador con los dispositivos conectados, su rutina DpcForIsr o CustomDpc es responsable de liberar el objeto de controlador mediante IoFreeController antes de completar el IRP actual y devuelve el control.
Las rutinas DpcForIsr y CustomDpc suelen ser responsables de registrar los errores de dispositivo que se produjeron durante el procesamiento de una solicitud determinada, reintentar la solicitud actual si es necesario y posible, y para establecer el bloque de estado de E/S y llamar a IoCompleteRequest para el IRP actual.
Si el controlador y el dispositivo admiten operaciones de E/S superpuestas, el controlador debe seguir las reglas para controlar las operaciones de E/S superpuestas.
La rutina DpcForIsr o CustomDpc de cualquier controlador normalmente completa el procesamiento de E/S solo para un subconjunto de los códigos de control de E/S públicos que el controlador debe admitir. En concreto, la rutina DPC completa las operaciones de las solicitudes de control de dispositivos con las siguientes características:
Solicitudes que cambian el estado del dispositivo físico
Solicitudes que requieren el retorno de información inherentemente volátil sobre el dispositivo físico