← Planificación de la CPU Bloque 9 · Planificación en tiempo real · Tema 35 de 44

Tema 35

Tiempo real en Linux

Linux soporta tiempo real a través de tres políticas: SCHED_FIFO, SCHED_RR y SCHED_DEADLINE. En este tema verás cómo funcionan, cómo se usan con chrt, cómo se observan con las herramientas del sistema, qué es la inversión de prioridades (uno de los problemas más graves de los sistemas de tiempo real) y cómo se resuelve.

1. Las políticas de tiempo real de Linux

Linux tiene tres políticas de tiempo real, además de la política normal (SCHED_OTHER):

PolíticaNombreTipoPrioridadesQuantum
SCHED_FIFOFirst-In, First-OutTiempo real1-99No
SCHED_RRRound RobinTiempo real1-99Sí
SCHED_DEADLINEEarliest Deadline FirstTiempo real0 (implícita)Por plazo
SCHED_OTHERCompletely Fair SchedulerNormal0 (nice -20 a +19)Dinámico
SCHED_BATCHBatchNormal0 (nice)Dinámico
SCHED_IDLEIdleNormal0Dinámico

Las políticas de tiempo real tienen prioridad sobre SCHED_OTHER: un proceso de tiempo real siempre se ejecuta antes que uno normal, siempre que esté listo. Entre procesos de tiempo real, se usa la prioridad numérica (mayor = más prioridad).

Las políticas de tiempo real requieren privilegios (CAP_SYS_NICE) para asignarse. Un usuario normal no puede lanzar un proceso de tiempo real sin los permisos adecuados.

Las políticas de tiempo real son absolutas

Un proceso SCHED_FIFO con prioridad 1 se ejecuta antes que cualquier proceso SCHED_OTHER, incluso con nice -20. Las clases de tiempo real tienen prioridad absoluta sobre la clase fair.

2. SCHED_FIFO

SCHED_FIFO es la política de tiempo real más simple: el proceso se ejecuta hasta que se bloquea, cede la CPU (sched_yield) o termina. No hay quantum. Es como FCFS pero con prioridades de tiempo real.

Características:

SCHED_FIFO es adecuado para tareas que necesitan ejecutarse sin interrupciones hasta que terminan su trabajo. Es el equivalente a RM (Rate Monotonic) en Linux.

Un proceso SCHED_FIFO con alta prioridad puede monopolizar la CPU si no se bloquea. Por eso, debe usarse con cuidado: un proceso de cálculo con SCHED_FIFO y prioridad alta puede bloquear a todos los demás.

3. SCHED_RR

SCHED_RR es igual que SCHED_FIFO, pero con un quantum. Si un proceso no termina en su quantum, se le quita la CPU y se le envía al final de la cola de su prioridad. Es Round Robin entre procesos de la misma prioridad.

Características:

SCHED_RR es adecuado para tareas que necesitan ejecutarse periódicamente pero no deben monopolizar la CPU. Es el equivalente a Round Robin con prioridades de tiempo real.

4. SCHED_DEADLINE

SCHED_DEADLINE implementa EDF (Earliest Deadline First) con garantías de tiempo real. El proceso especifica su período, tiempo de ejecución y plazo, y el sistema garantiza que se cumplen (si es posible).

Características:

SCHED_DEADLINE es la política más avanzada de Linux para tiempo real. Implementa EDF con las garantías formales que se estudian en el tema 33.

SCHED_DEADLINE requiere parámetros

Para usar SCHED_DEADLINE, el proceso debe especificar su período, tiempo de ejecución y plazo mediante la syscall sched_setattr. El sistema verifica que el conjunto sea planificable antes de aceptar. Si no lo es, la syscall falla con EBUSY.

5. Comparación de las políticas

AspectoSCHED_FIFOSCHED_RRSCHED_DEADLINE
QuantumNoSíPor plazo
PrioridadFija (1-99)Fija (1-99)Dinámica (por plazo)
GarantíasNoNoSí
AdmisiónSin controlSin controlControlada
Uso típicoTareas críticasTareas periódicasTareas con plazos
ComplejidadBajaBajaAlta

6. Usar chrt

La herramienta chrt permite lanzar procesos con una política de tiempo real o cambiar la política de un proceso existente:

terminal · chrt
# Lanzar un proceso con SCHED_FIFO y prioridad 50
$ chrt -f 50 ./mi_programa

# Lanzar con SCHED_RR y prioridad 50
$ chrt -r 50 ./mi_programa

# Lanzar con SCHED_DEADLINE (runtime 2ms, deadline 10ms, period 10ms)
$ chrt -d --sched-runtime 2000000 --sched-deadline 10000000 --sched-period 10000000 0 ./mi_programa

# Ver la política de un proceso
$ chrt -p PID
pid 1234's current scheduling policy: SCHED_FIFO
pid 1234's current scheduling priority: 50

# Cambiar la política de un proceso existente
$ chrt -p -f 80 1234

# Listar las políticas disponibles
$ chrt -m
SCHED_OTHER min/max priority    : 0/0
SCHED_FIFO min/max priority     : 1/99
SCHED_RR min/max priority       : 1/99
SCHED_BATCH min/max priority    : 0/0
SCHED_IDLE min/max priority     : 0/0
SCHED_DEADLINE min/max priority  : 0/0

Las prioridades de tiempo real van del 1 al 99 (mayor = más prioridad). La prioridad 0 es para SCHED_OTHER (la clase normal). Un proceso con prioridad 99 tiene la máxima prioridad del sistema.

Para usar chrt con SCHED_FIFO o SCHED_RR, se necesita privilegio (root o CAP_SYS_NICE). Para SCHED_DEADLINE, también se necesita privilegio.

7. Prioridades de tiempo real

Las prioridades de tiempo real se organizan en 99 niveles. Las políticas de tiempo real tienen prioridad sobre SCHED_OTHER, pero dentro de las políticas de tiempo real, la prioridad numérica determina el orden.

La convención es:

Un proceso de tiempo real con prioridad 1 se ejecuta antes que cualquier proceso normal, pero después de un proceso de tiempo real con prioridad 2.

La asignación de prioridades de tiempo real es responsabilidad del programador. Un error (por ejemplo, asignar prioridad 99 a un proceso que no la necesita) puede causar que otros procesos de tiempo real no se ejecuten.

La prioridad 99 es peligrosa

Un proceso con prioridad 99 que no se bloquea nunca puede monopolizar la CPU, bloqueando a todos los demás procesos (incluso los de tiempo real con menor prioridad). Usar prioridad 99 solo para procesos críticos y breves.

8. Inversión de prioridades

La inversión de prioridades (priority inversion) ocurre cuando un proceso de alta prioridad se bloquea esperando un recurso que tiene un proceso de baja prioridad. El proceso de alta prioridad no puede ejecutarse hasta que el de baja prioridad libere el recurso, pero el de baja prioridad no puede ejecutarse porque hay procesos de prioridad media en la CPU.

La inversión de prioridades es uno de los problemas más graves de los sistemas de tiempo real. Puede causar que un proceso de alta prioridad espere indefinidamente, incumpliendo su plazo.

El problema ocurre porque la prioridad del proceso de baja prioridad no se eleva cuando el proceso de alta prioridad se bloquea. El proceso de baja prioridad mantiene su prioridad original y puede ser preemptado por procesos de prioridad media.

Inversión de prioridades ≠ inanición

La inanición ocurre cuando un proceso espera indefinidamente porque siempre hay otros con mayor prioridad. La inversión de prioridades ocurre cuando un proceso de alta prioridad se bloquea por un recurso que tiene un proceso de baja prioridad. Son problemas distintos.

9. Un ejemplo de inversión

Tres procesos:

ProcesoPrioridadAcción
H (alta)90Necesita el recurso R.
M (media)50Proceso de cálculo.
L (baja)10Tiene el recurso R.

Secuencia de eventos:

  1. t = 0: L se ejecuta y adquiere el recurso R. adquirir
  2. t = 1: H llega y necesita R. H se bloquea esperando R. L sigue ejecutándose. bloquear
  3. t = 2: M llega. M tiene prioridad 50 > L (10). M preempta a L. L deja de ejecutarse (y no libera R). preemptar
  4. t = 2 a 10: M se ejecuta. L no se ejecuta (preemptado). H sigue bloqueado esperando R. bloqueo
  5. t = 10: M termina. L se ejecuta de nuevo y libera R. H se desbloquea y se ejecuta. liberar

El problema: H (prioridad 90) esperó 9 unidades de tiempo porque M (prioridad 50) se ejecutó antes que L (prioridad 10). La prioridad de H fue «invertida»: un proceso de prioridad media se ejecutó antes que uno de alta prioridad.

En un sistema de tiempo real, esto puede causar que H incumpla su plazo.

10. Soluciones a la inversión

Hay dos soluciones principales a la inversión de prioridades:

SoluciónCómo funcionaVentajaDesventaja
Herencia de prioridadCuando un proceso de alta prioridad se bloquea esperando un recurso, el proceso que tiene el recurso hereda la prioridad del proceso bloqueado.Simple, efectiva.Solo funciona con un nivel de anidamiento.
Techo de prioridadCuando un proceso adquiere un recurso, su prioridad se eleva al techo (la prioridad más alta de todos los procesos que pueden usar ese recurso).Previene la inversión antes de que ocurra.Requiere conocer las prioridades de todos los procesos que usan el recurso.

En el ejemplo anterior, con herencia de prioridad:

  1. t = 0: L adquiere R con prioridad 10. adquirir
  2. t = 1: H llega y necesita R. H se bloquea. L hereda la prioridad de H (90). heredar
  3. t = 2: M llega. M tiene prioridad 50 < L (90, heredada). M no preempta a L. L sigue ejecutándose. no preemptar
  4. t = 3: L libera R. L vuelve a prioridad 10. H se desbloquea y se ejecuta. liberar

Con herencia de prioridad, H espera solo 2 unidades en lugar de 9. La inversión se evita.

11. Herencia de prioridad en Linux

Linux implementa la herencia de prioridad a través de:

C · mutex con herencia de prioridad
#include <pthread.h>

pthread_mutex_t mutex;
pthread_mutexattr_t attr;

/* Configurar el mutex para herencia de prioridad. */
pthread_mutexattr_init(&attr);
pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT);
pthread_mutex_init(&mutex, &attr);

La herencia de prioridad es esencial para los sistemas de tiempo real en Linux. Sin ella, la inversión de prioridades puede causar incumplimiento de plazos.

12. Observar en Linux

Para observar las políticas de tiempo real en Linux:

terminal · observar tiempo real
# Ver las políticas de todos los procesos
$ ps -e -o pid,cls,pri,ni,rtprio,comm | grep -v TS

# Ver la política de un proceso específico
$ chrt -p 1234

# Ver los procesos de tiempo real
$ ps -e -o pid,cls,rtprio,comm | grep -E 'FF|RR|DL'

# Ver la latencia del sistema (con cyclictest)
$ cyclictest -p 99 -t 1 -n -l 1000
# /dev/cpu_dma_latency set to 0us
# policy: fifo: loadavg: ...
# T: 0 ( 1234) P:99 I:1000 C: 1000 Min: 1 Act: 2 Avg: 3 Max: 15

cyclictest mide la latencia del sistema: el tiempo que tarda en responder a una interrupción periódica. Es la herramienta estándar para evaluar sistemas de tiempo real en Linux.

13. Simulador interactivo

Este simulador muestra la inversión de prioridades y cómo la herencia la resuelve. Tres procesos: H (alta), M (media), L (baja) con un recurso compartido:

Simulador · inversión de prioridades

ProcesoPrioridadInicioFinTiempo de espera

14. Resumen

15. Preguntas de repaso

Intenta responder cada una antes de abrir la respuesta.

1. ¿Qué es SCHED_FIFO?

Política de tiempo real sin quantum: el proceso se ejecuta hasta que se bloquea o cede la CPU.

2. ¿Qué es SCHED_RR?

Política de tiempo real con quantum: Round Robin entre procesos de la misma prioridad.

3. ¿Qué es SCHED_DEADLINE?

Política basada en plazos: el proceso especifica su plazo y el sistema lo cumple.

4. ¿Qué rango de prioridades tienen las políticas de tiempo real?

1 al 99 (mayor = más prioridad).

5. ¿Qué es la inversión de prioridades?

Un proceso de alta prioridad se bloquea esperando un recurso que tiene un proceso de baja prioridad.

6. ¿Cómo se resuelve la inversión de prioridades?

Con herencia de prioridad o techo de prioridad.

7. ¿Qué hace la herencia de prioridad?

El proceso que tiene el recurso hereda la prioridad del proceso bloqueado.

8. ¿Qué herramienta mide la latencia del sistema?

cyclictest.

9. ¿Qué syscall se usa para SCHED_DEADLINE?

sched_setattr.

10. ¿Implementa Linux la herencia de prioridad?

Sí, en mutexes (PTHREAD_PRIO_INHERIT) y futexes.

Para practicar

  1. Lanza un proceso con chrt -f 50 y observa su política con chrt -p.
  2. Usa cyclictest para medir la latencia de tu sistema.
  3. Escribe un programa que demuestre la inversión de prioridades.
  4. Implementa la herencia de prioridad con pthreads.
  5. Compara SCHED_FIFO y SCHED_RR para el mismo conjunto de procesos.
  6. Investiga cómo SCHED_DEADLINE verifica la planificabilidad.