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ítica | Nombre | Tipo | Prioridades | Quantum |
|---|---|---|---|---|
| SCHED_FIFO | First-In, First-Out | Tiempo real | 1-99 | No |
| SCHED_RR | Round Robin | Tiempo real | 1-99 | Sí |
| SCHED_DEADLINE | Earliest Deadline First | Tiempo real | 0 (implícita) | Por plazo |
| SCHED_OTHER | Completely Fair Scheduler | Normal | 0 (nice -20 a +19) | Dinámico |
| SCHED_BATCH | Batch | Normal | 0 (nice) | Dinámico |
| SCHED_IDLE | Idle | Normal | 0 | Diná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.
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:
- Sin quantum: el proceso se ejecuta hasta que se bloquea o cede.
- Prioridades fijas: la prioridad no cambia durante la ejecución.
- Apropiativo entre prioridades: si llega un proceso de mayor prioridad, interrumpe al actual.
- No apropiativo dentro de la misma prioridad: si dos procesos tienen la misma prioridad, el primero en llegar se ejecuta hasta que se bloquea.
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:
- Con quantum: el proceso se ejecuta durante un quantum y luego cede la CPU.
- Round Robin dentro de la prioridad: los procesos de la misma prioridad se turnan.
- Apropiativo entre prioridades: igual que SCHED_FIFO.
- Quantum típico: 100 ms (configurable).
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:
- Basado en plazos: el proceso especifica su plazo y el sistema lo cumple.
- Garantías formales: el sistema verifica que el conjunto sea planificable antes de aceptar.
- Admisión controlada: si no hay suficiente CPU, el sistema rechaza la tarea.
- Sin prioridad numérica: la prioridad se determina por el plazo.
- Parámetros: runtime (tiempo de ejecución), deadline (plazo), period (período).
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.
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
| Aspecto | SCHED_FIFO | SCHED_RR | SCHED_DEADLINE |
|---|---|---|---|
| Quantum | No | Sí | Por plazo |
| Prioridad | Fija (1-99) | Fija (1-99) | Dinámica (por plazo) |
| Garantías | No | No | Sí |
| Admisión | Sin control | Sin control | Controlada |
| Uso típico | Tareas críticas | Tareas periódicas | Tareas con plazos |
| Complejidad | Baja | Baja | Alta |
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:
# 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:
- Prioridad 1-99: tiempo real (SCHED_FIFO, SCHED_RR). Mayor número = mayor prioridad.
- Prioridad 0: clase normal (SCHED_OTHER, SCHED_BATCH, SCHED_IDLE).
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.
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.
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:
| Proceso | Prioridad | Acción |
|---|---|---|
| H (alta) | 90 | Necesita el recurso R. |
| M (media) | 50 | Proceso de cálculo. |
| L (baja) | 10 | Tiene el recurso R. |
Secuencia de eventos:
- t = 0: L se ejecuta y adquiere el recurso R. adquirir
- t = 1: H llega y necesita R. H se bloquea esperando R. L sigue ejecutándose. bloquear
- t = 2: M llega. M tiene prioridad 50 > L (10). M preempta a L. L deja de ejecutarse (y no libera R). preemptar
- t = 2 a 10: M se ejecuta. L no se ejecuta (preemptado). H sigue bloqueado esperando R. bloqueo
- 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ón | Cómo funciona | Ventaja | Desventaja |
|---|---|---|---|
| Herencia de prioridad | Cuando 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 prioridad | Cuando 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:
- t = 0: L adquiere R con prioridad 10. adquirir
- t = 1: H llega y necesita R. H se bloquea. L hereda la prioridad de H (90). heredar
- t = 2: M llega. M tiene prioridad 50 < L (90, heredada). M no preempta a L. L sigue ejecutándose. no preemptar
- 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:
- Mutexes con PTHREAD_PRIO_INHERIT: en pthreads, un mutex puede configurarse para heredar prioridad cuando un proceso de alta prioridad se bloquea.
- Futexes con prioridad heredada: en el núcleo, los futexes (fast user-space mutexes) soportan herencia de prioridad.
- rt_mutex: el núcleo de Linux tiene mutexes de tiempo real (rt_mutex) que implementan 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:
# 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
| Proceso | Prioridad | Inicio | Fin | Tiempo de espera |
|---|
14. Resumen
- Linux tiene tres políticas de tiempo real: SCHED_FIFO, SCHED_RR y SCHED_DEADLINE.
- SCHED_FIFO: sin quantum, apropiativo entre prioridades.
- SCHED_RR: con quantum, Round Robin dentro de la prioridad.
- SCHED_DEADLINE: basado en plazos, con garantías formales.
- Las prioridades de tiempo real van del 1 al 99.
- chrt permite lanzar y modificar procesos de tiempo real.
- La inversión de prioridades ocurre cuando un proceso de alta prioridad se bloquea por un recurso de uno de baja prioridad.
- La herencia de prioridad y el techo de prioridad son las soluciones.
- Linux implementa la herencia de prioridad en mutexes y futexes.
- cyclictest mide la latencia del sistema.
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
- Lanza un proceso con chrt -f 50 y observa su política con chrt -p.
- Usa cyclictest para medir la latencia de tu sistema.
- Escribe un programa que demuestre la inversión de prioridades.
- Implementa la herencia de prioridad con pthreads.
- Compara SCHED_FIFO y SCHED_RR para el mismo conjunto de procesos.
- Investiga cómo SCHED_DEADLINE verifica la planificabilidad.