Siempre preemptible y siempre interrumpible

El objetivo del diseño preemptible e interrumpible del sistema operativo es maximizar el rendimiento del sistema. Cualquier subproceso puede ser reemplazado por un subproceso con una prioridad más alta y cualquier rutina de servicio de interrupción del controlador (ISR) se puede interrumpir mediante una rutina que se ejecuta en un nivel de solicitud de interrupción superior (IRQL).

El componente de kernel determina cuándo se ejecuta una secuencia de código, según uno de estos criterios de priorización:

  • Esquema de prioridad en tiempo de ejecución definido por el kernel para subprocesos.

    Cada subproceso del sistema tiene un atributo de prioridad asociado. En general, la mayoría de los subprocesos tienen atributos de prioridad variable : siempre son preferentes y están programados para ejecutar round robin con todos los demás subprocesos que están actualmente en el mismo nivel de prioridad. Algunos subprocesos tienen atributos de prioridad en tiempo real : estos subprocesos críticos para el tiempo se ejecutan hasta su finalización a menos que un subproceso tenga un atributo de prioridad en tiempo real mayor. La arquitectura de Microsoft Windows no proporciona un sistema inherentemente en tiempo real.

    Sea cual sea su atributo de prioridad, cualquier subproceso del sistema se puede reemplazar cuando se producen interrupciones de hardware y ciertos tipos de interrupciones de software.

  • El nivel de solicitud de interrupción definido por el kernel (IRQL) al que se asigna un vector de interrupción determinado en una plataforma determinada.

    El kernel da prioridad a las interrupciones de hardware y software para que algún código en modo kernel, incluida la mayoría de los controladores, se ejecute en IRQL más altos, lo que hace que tenga una prioridad de programación más alta que otros subprocesos del sistema. El IRQL concreto en el que se ejecuta un fragmento de código de controlador en modo kernel viene determinado por la prioridad de hardware de su dispositivo subyacente.

    El código en modo kernel siempre es interrumpible: una interrupción con un valor IRQL superior puede producirse en cualquier momento, lo que provoca que otro fragmento de código en modo kernel que tenga un IRQL asignado por el sistema superior se ejecute inmediatamente en ese procesador. Sin embargo, cuando un fragmento de código se ejecuta en un IRQL determinado, el kernel enmascara todos los vectores de interrupción con un valor IRQL menor o igual en el procesador.

El nivel irQL más bajo se denomina PASSIVE_LEVEL. En este nivel, no se enmascara ningún vector de interrupción. Los subprocesos se suelen ejecutar en IRQL=PASSIVE_LEVEL. Los siguientes niveles irQL más altos son para interrupciones de software. Estos niveles incluyen APC_LEVEL, DISPATCH_LEVEL o, para la depuración del kernel, WAKE_LEVEL. Las interrupciones del dispositivo todavía tienen valores IRQL más altos. El kernel reserva los valores irQL más altos para las interrupciones críticas del sistema, como las del reloj del sistema o los errores de bus.

Algunas rutinas de soporte técnico del sistema se ejecutan en IRQL=PASSIVE_LEVEL, ya sea porque se implementan como código paginable o acceden a datos paginables, o porque algunos componentes del modo kernel configuran sus propios subprocesos.

De forma similar, algunas rutinas de controlador estándar normalmente se ejecutan en IRQL=PASSIVE_LEVEL. Sin embargo, varias rutinas de controlador estándar se ejecutan en IRQL=DISPATCH_LEVEL o, para un controlador de nivel inferior, en el IRQL del dispositivo (también denominado DIRQL). Para obtener más información sobre los IRQL, consulte Administración de prioridades de hardware.

Todas las rutinas de un controlador son interrumpibles. Esto incluye cualquier rutina que se ejecute en un IRQL mayor que PASSIVE_LEVEL. Cualquier rutina que se ejecute en un IRQL determinado conserva el control del procesador solo si no se produce ninguna interrupción para un IRQL superior mientras se ejecuta esa rutina.

A diferencia de los controladores de algunos sistemas operativos de equipos personales más antiguos, un ISR del controlador de Microsoft Windows nunca es una rutina grande y compleja que realiza la mayoría del procesamiento de E/S del controlador. Esto se debe a que cualquier rutina de servicio de interrupción del controlador (ISR) se puede interrumpir mediante otra rutina (por ejemplo, por otro ISR del controlador) que se ejecuta en un IRQL superior. Por lo tanto, el ISR del controlador no conserva necesariamente el control de una CPU, sin interrupciones, desde el principio de su ruta de acceso de ejecución hasta el final.

En los controladores de Windows, un ISR normalmente guarda información de estado de hardware, pone en cola una llamada a procedimiento diferido (DPC) y, a continuación, se cierra rápidamente. Más adelante, el sistema pone en cola el DPC del controlador para que el controlador pueda completar las operaciones de E/S en un IRQL inferior (DISPATCH_LEVEL). Para un buen rendimiento general del sistema, todas las rutinas que se ejecutan en irQLs altos deben renunciar rápidamente al control de la CPU.

En Windows, todos los subprocesos tienen un contexto de subproceso. Este contexto consta de información que identifica el proceso que posee el subproceso, además de otras características, como los derechos de acceso del subproceso.

En general, solo se llama a un controlador de nivel superior en el contexto del subproceso que solicita la operación de E/S actual del controlador. Un controlador de nivel intermedio o de nivel inferior nunca puede suponer que se está ejecutando en el contexto del subproceso que solicitó su operación de E/S actual.

Por lo tanto, las rutinas de controlador normalmente se ejecutan en un contexto de subproceso arbitrario: el contexto de cualquier subproceso actual cuando se llama a una rutina de controlador estándar. Por motivos de rendimiento (para evitar conmutadores de contexto), muy pocos controladores configuran sus propios subprocesos.