Uso de una rutina ioTimer

Mientras el temporizador del objeto de dispositivo asociado está habilitado, se llama a la rutina IoTimer aproximadamente una vez por segundo. Sin embargo, dado que los intervalos en los que se llama a cada rutina de IoTimer dependen de la resolución del reloj del sistema, no suponga que se llamará a una rutina de IoTimer precisamente en un límite de un segundo.

Nota Se llama a una rutina de IoTimer , como todas las rutinas de DPC, en IRQL = DISPATCH_LEVEL. Mientras se ejecuta una rutina DPC, se impide que todos los subprocesos se ejecuten en el mismo procesador. Los desarrolladores de controladores deben diseñar cuidadosamente sus rutinas de IoTimer para que se ejecuten tan brevemente como sea posible.

Quizás el uso más común de una rutina de IoTimer es agotar el tiempo de espera de las operaciones de E/S del dispositivo para un IRP. Considere el siguiente escenario para usar una rutina ioTimer como temporizador en ejecución dentro de un controlador de dispositivo:

  1. Cuando inicia el dispositivo, el controlador inicializa un contador de temporizador en la extensión del dispositivo en -1, lo que indica que no hay operaciones de E/S de dispositivo actuales y llama a IoStartTimer justo antes de que devuelva STATUS_SUCCESS.

    Cada vez que se llama a la rutina IoTimer , comprueba si el contador del temporizador es -1 y, si es así, devuelve el control .

  2. La rutina StartIo del controlador inicializa el contador del temporizador en la extensión del dispositivo a un límite superior, además de un segundo adicional en caso de que se haya ejecutado la rutina IoTimer . A continuación, usa KeSynchronizeExecution para llamar a una rutina de SynchCritSection_1 , que programa el dispositivo físico para la operación solicitada por el IRP actual.

  3. El ISR del controlador restablece el contador del temporizador a -1 antes de poner en cola la rutina DpcForIsr del controlador o una rutina CustomDpc .

  4. Cada vez que se llama a la rutina IoTimer , comprueba si el ISR ha restablecido el contador del temporizador en -1 y, si es así, devuelve el control . Si no es así, la rutina IoTimer usa KeSynchronizeExecution para llamar a una rutina de SynchCritSection_2 , que ajusta el contador del temporizador por un número determinado por el controlador de segundos.

  5. La rutina SynchCritSection_2 devuelve TRUE a la rutina IoTimer siempre que la solicitud actual aún no haya agotado el tiempo de espera. Si el contador del temporizador va a cero, la rutina SynchCritSection_2 restablece el contador de temporizador a un valor de tiempo de espera de restablecimiento determinado por el controlador, establece una marca de restablecimiento esperada para sí misma (y para DpcForIsr) en su área de contexto, intenta restablecer el dispositivo y devuelve TRUE.

    Se volverá a llamar a la rutina SynchCritSection_2 si su operación de restablecimiento también agota el tiempo de espera en el dispositivo, cuando devuelve FALSE. Si el restablecimiento se realiza correctamente, la rutina DpcForIsr determina que el dispositivo se ha restablecido desde la marca de restablecimiento esperado y vuelve a intentar la solicitud, repitiendo las acciones de la rutina StartIo como se describe en el paso 2.

  6. Si la rutina de SynchCritSection_2 devuelve FALSE, la rutina IoTimer supone que el dispositivo físico está en un estado desconocido porque ya se ha producido un error al intentar restablecerlo. En estas circunstancias, la rutina IoTimer pone en cola una rutina CustomDpc y devuelve. Esta rutina CustomDpc registra un error de E/S del dispositivo, llama a IoStartNextPacket, produce un error en el IRP actual y devuelve.

Si el ISR de este controlador de dispositivo restablece el contador del temporizador compartido a -1, como se describe en el paso 3, la rutina DpcForIsr del controlador completa el procesamiento de E/S controlado por interrupciones del IRP actual. El contador del temporizador de restablecimiento indica que esta operación de E/S del dispositivo no ha agotado el tiempo de espera, por lo que la rutina IoTimer no necesita cambiar el contador del temporizador.

En la mayoría de las circunstancias, la rutina de SynchCritSection_2 anterior simplemente disminuye el contador del temporizador. La rutina SynchCritSection_2 intenta restablecer el dispositivo solo si se agota el tiempo de espera de la operación de E/S actual, que se indica cuando el contador del temporizador va a cero. Y solo si ya se ha producido un error en un intento de restablecer el dispositivo, la rutina SynchCritSection_2 devuelve FALSE a la rutina IoTimer .

Por lo tanto, tanto la rutina ioTimer anterior como su asistente SynchCritSection_2 rutina tardan muy poco tiempo en ejecutarse en circunstancias normales. Mediante el uso de una rutina de IoTimer de esta manera, un controlador de dispositivo garantiza que cada solicitud de E/S de dispositivo válida se pueda reintentar, si es necesario, y que una rutina CustomDpc producirá un error irP solo si un error de hardware irrecuperable impide que se cumpla el IRP. Además, el controlador proporciona esta funcionalidad a muy poco costo en tiempo de ejecución.

La simplicidad del escenario anterior depende de un dispositivo que realice solo una operación a la vez y en un controlador que normalmente no se superponga a las operaciones de E/S. Un controlador que lleva a cabo operaciones de E/S de dispositivo superpuestas o un controlador de nivel superior que usa una rutina de IoTimer para agotar el tiempo de espera de un conjunto de IRP asignados por controladores enviados a más de una cadena de controladores inferiores, tendría escenarios de tiempo de espera más complejos para administrar.