1. La letra del estado
En linux, el estado de un proceso se representa por una letra, Que aparece en la columna STAT de ps y en el campo State: de /proc/PID/status. Esa letra es una traduccion del campo state del task_struct.
| Letra | Nombre | Significado |
|---|---|---|
| R | Running | Ejecutandose en la CPU o listo. Linux no distingue entre ambos. |
| S | Sleeping | Dormido, esperando un evento. Interruptible por senales. |
| D | Uninterruptible sleep | Dormido en E/S de disco. No se interrumpe por senales. |
| T | Stopped | Detenido por una senal (SIGSTOP, SIGTSTP) o por el depurador. |
| Z | Zombie | Termino pero su padre no lo recogio. |
| t | Tracing stop | Detenido por un depurador (ptrace). |
| X | Dead | Siendo destruido. Estado transitorio. |
La razon por la que linux no distingue entre listo y en ejecución es práctica: desde fuera del núcleo, un proceso en cualquiera de los dos estados esta activo, y la distincion cambia en microsegúndos.
2. R: en ejecución o listo
Un proceso en estado R es el que esta usando la CPU o esta en la cola de listos. Para provocarlo, un bucle que use la CPU Sin bloquearse:
#define _POSIX_C_SOURCE 200809L
#include
#include
int main(void)
{
printf("PID: %d - estado R\n", (int) getpid());
volatile unsigned long x = 0;
for (;;) x++;
return 0;
}
$ gcc -std=c17 -Wall -Wextra -o estado_r estado_r.c
$ ./estado_r (en segúndo plano)
[1] 812
PID: 812 - estado R
$ ps -o pid,stat,pcpu,comm -p 812
PID STAT %CPU COMMAND
812 R+ 99.9 estado_r
$ pkill estado_r
El porcentaje de CPU cerca de 100 y el estado R+ confirman que el proceso esta consumiendo CPU.
3. S: dormido interruptible
Un proceso en estado S esta dormido: llamo a una operación que lo bloquea hasta que ocurra un evento. Es interruptible porque puede despertarse por una senal.
Causas comunes: sleep(), read() en terminal, wait(), pause(), select() y poll().
#define _POSIX_C_SOURCE 200809L
#include
#include
int main(void)
{
printf("PID: %d - estado S\n", (int) getpid());
for (;;) {
printf("durmiendo 30 Segúndos...\n");
fflush(stdout);
sleep(30);
}
return 0;
}
$ gcc -std=c17 -Wall -Wextra -o estado_s estado_s.c
$ ./estado_s (en segúndo plano)
[1] 820
PID: 820 - estado S
$ ps -o pid,stat,wchan,comm -p 820
PID STAT WCHAN COMMAND
820 S+ hrtimer_nanosleep estado_s
$ kill -TERM 820
La columna WCHAN muestra hrtimer_nanosleep: el proceso esta dormido en el temporizador de alta resolución del núcleo. Como es interruptible, la senal SIGTERM lo despierta inmediatamente.
4. D: dormido ininterruptible
Un proceso en estado D esta dormido en una operación de E/S, Tipicamente de disco, y no puede despertarse por senales. Ni SIGKILL ni SIGTERM lo interrumpen: Sólo cuándo la operación de E/S termina, el núcleo lo despierta.
El estado D existe para proteger la consistencia de los datos: Sí un proceso esta en medio de una escritura al disco y se le interrumpe, podria dejar el sistema de archivos en un estado inconsistente.
Las causas tipicas son: lecturas o escrituras a disco que tardan, Operaciónes de E/S directa (O_DIRECT), espera de un bloqueo de archivo, problemás de hardware.
$ dd if=/dev/sda of=/dev/null bs=1M (en segúndo plano)
[1] 830
$ ps -o pid,stat,wchan,comm -p 830
PID STAT WCHAN COMMAND
830 D+ io_schedule dd
El WCHAN muestra io_schedule: el proceso esta en la cola de E/S del núcleo. Si intentas matarlo con kill -9, no pasa nada hasta que la operación termine.
Si un proceso se queda en estado D indefinidamente (por un disco que no responde), la unica forma de eliminarlo es reiniciar el sistema o arreglar el problema de hardware.
5. T: detenido
Un proceso en estado T esta detenido: recibio una senal que lo detiene (SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU) o esta siendo controlado por un depurador. Mientras esta detenido, no se ejecuta y no usa CPU. Solo se reanuda cuándo recibe SIGCONT.
Las senales que detienen un proceso son: SIGSTOP (incondicional), SIGTSTP (desde terminal, Ctrl+Z), SIGTTIN (proceso en segúndo plano intenta leer), SIGTTOU (proceso en segúndo plano intenta escribir).
#define _POSIX_C_SOURCE 200809L
#include
#include
#include
int main(void)
{
printf("PID: %d - enviando SIGSTOP a sí mismo\n", (int) getpid());
fflush(stdout);
raise(SIGSTOP);
printf("Reanudado con SIGCONT. Terminando.\n");
return 0;
}
$ gcc -std=c17 -Wall -Wextra -o estado_t estado_t.c
$ ./estado_t (en segúndo plano)
[1] 840
PID: 840 - enviando SIGSTOP a sí mismo
$ ps -o pid,stat,wchan,comm -p 840
PID STAT WCHAN COMMAND
840 T+ - estado_t
$ kill -CONT 840
Reanudado con SIGCONT. Terminando.
Desde la shell, Ctrl+Z envia SIGTSTP al proceso en primer plano. Luego se puede reanudar en primer plano con fg o en segúndo plano con bg.
6. Z: zombi
Un proceso en estado Z es un zombi: Terminó su ejecución pero su padre no lo recogio. No ejecuta código, no usa memoria (Más alla del PCB minimo) y no responde a senales. Solo ocupa una entrada en la tabla de procesos, esperando que el padre llame a wait() o waitpid().
En la salida de ps, el nombre del proceso aparece entre corchetes, Como [worker], porque el núcleo ya libero el espacio de memoria que contenia el nombre original.
#define _POSIX_C_SOURCE 200809L
#include
#include
#include
int main(void)
{
pid_t pid = fork();
if (pid < 0) { perror("fork"); return 1; }
if (pid == 0) {
printf("Hijo %d terminando\n", (int) getpid());
_exit(0);
}
printf("Padre %d. Hijo %d quedara zombi.\n",
(int) getpid(), (int) pid);
printf("Observa con: ps -o pid,ppid,stat,comm -p %d\n", (int) pid);
sleep(60);
wait(NULL);
printf("Hijo recogido. Terminando.\n");
return 0;
}
$ gcc -std=c17 -Wall -Wextra -o estado_z estado_z.c
$ ./estado_z (en segúndo plano)
[1] 850
Padre 850. Hijo 851 Quedara zombi.
Hijo 851 terminando
$ ps -o pid,ppid,stat,comm -p 851
PID PPID STAT COMMAND
851 850 Z [estado_z]
$ grep state /proc/851/status
State: Z (zombie)
$ kill 850
La entrada [estado_z] entre corchetes y el estado Z confirman que el proceso es un zombi.
7. t y X: tracing stop y muerto
t: tracing stop
Un proceso en estado t (minuscula) esta detenido por un depurador que usa ptrace. Es similar a T, pero especifico de la depuracion. Cuando adjuntas gdb a un proceso en ejecución, el proceso pasa a estado t mientras el depurador lo controla.
X: dead
Un proceso en estado X esta siendo destruido. Es un estado transitorio que casí nunca se observa en la práctica, porque el proceso pasa por el muy rápidamente antes de desaparecer.
8. Los modificadores de la letra
La letra del estado puede ir seguida de uno o más modificadores que anaden información:
| Modificador | Significado |
|---|---|
| + | El proceso esta en el grupo de procesos en primer plano de su terminal. |
| s | El proceso es el lider de su sesion. |
| l | El proceso es multihilo (tiene más de un hilo). |
| < | El proceso tiene prioridad alta (nice negativo). |
| N | El proceso tiene prioridad baja (nice positivo). |
Por ejemplo, Ss+ Significa: dormido, lider de sesion, en primer plano. Rl significa: ejecutandose, multihilo.
9. El estado en /proc/PID/status
En /proc/PID/status, el estado aparece en la linea state, con la letra y una descripción:
$ grep state /proc/self/status
State: S (sleeping)
$ grep state /proc/812/status
State: R (running)
En /proc/PID/stat, el tercer campo es la letra del estado, en formato compacto para programas:
$ awk "{print \$3}" /proc/self/stat
S
10. WCHAN y /proc/PID/stack
La columna WCHAN (wait channel) de ps muestra en que función del núcleo esta dormido el proceso, Sí esta bloqueado. Si el proceso esta en R, aparece un guion (-). Es una pista útil para saber por que un proceso esta bloqueado.
Además, /proc/PID/stack muestra la pila de llamadas del núcleo para ese proceso, lo que permite ver exactamente en que función se bloqueo:
$ cat /proc/820/stack
[
Leer /proc/PID/stack requiere privilegios de root o ser el propietario del proceso, Según la configuración del kernel.
11. Programás que provocan cada estado
El siguiente programa hace distintas cosas para provocar varios estados, y permite observarlos con ps desde otra terminal:
#define _POSIX_C_SOURCE 200809L
#include
#include
#include
#include
int main(void)
{
printf("PID: %d\n", (int) getpid());
printf("Observa con: ps -o pid,stat,wchan,comm -p %d\n", (int) getpid());
/* 1. Estado R: usar la CPU */
printf("[1] Usando la CPU durante 5 Segúndos (R)...\n");
volatile unsigned long x = 0;
for (int i = 0; i < 5; i++) {
for (volatile int j = 0; j < 100000000; j++) x++;
sleep(1);
}
/* 2. Estado S: dormir */
printf("[2] Durmiendo 10 Segúndos (S)...\n");
sleep(10);
/* 3. Estado T: detenerse */
printf("[3] Deteniendose con SIGSTOP. Envia SIGCONT para continuar.\n");
fflush(stdout);
raise(SIGSTOP);
printf("[4] Continuando tras SIGCONT.\n");
printf("[5] Terminando.\n");
return 0;
}
Al ejecutarlo, puedes observar desde otra terminal como cambia el estado:
$ gcc -std=c17 -Wall -Wextra -o estados estados.c
$ ./estados (en segúndo plano)
[1] 710
PID: 710
$ ps -o pid,stat,wchan,comm -p 710
PID STAT WCHAN COMMAND
710 R+ - estados
$ sleep 6; ps -o pid,stat,wchan,comm -p 710
PID STAT WCHAN COMMAND
710 S+ hrtimer_nanosleep estados
$ sleep 12; ps -o pid,stat,wchan,comm -p 710
PID STAT WCHAN COMMAND
710 T+ - estados
$ kill -CONT 710
12. Cómo observar los estados en la práctica
Algunas tetécnicas utiles para observar los estados de los procesos:
ps -e -o stat,comm | sort | uniq -c: cuenta cuántos procesos hay en cada estado.watch -n 1 "ps -o pid,stat,wchan,comm -p PID": observa un proceso en tiempo real.topy pulsar 1: muestra cada núcleo y los estados de los procesos.cat /proc/PID/stack: muestra la pila del núcleo del proceso.
13. Resumen
- Linux representa el estado de un proceso con una letra en la columna STAT de ps.
- R: en ejecución o listo. S: dormido interruptible. D: dormido ininterruptible. T: detenido. Z: zombi. t: tracing stop. X: muerto.
- Los modificadores (+, s, l, menor que, N) anaden información sobre primer plano, Sesion, hilos y prioridad.
- El estado también se puede consultar en /proc/PID/status (campo state) y en /proc/PID/stat.
- WCHAN muestra en que función del núcleo esta dormido un proceso bloqueado.
- /proc/PID/stack muestra la pila de llamadas del núcleo del proceso.
14. Preguntas de repaso
Intenta responder cada una antes de abrir la respuesta.
1. Qué letra muestra ps para un proceso que usa la CPU?
La letra R (Running), Que incluye tanto los procesos ejecutandose como los que estan listos para ejecutarse.
2. Qué diferencia hay entre S y D?
S es dormido interruptible (puede despertarse por senales). D es dormido ininterruptible (no puede despertarse por senales, Sólo cuándo termina la E/S).
3. Se puede matar un proceso en estado D?
No con senales, ni siquiera SIGKILL. Solo cuándo la operación de E/S termina. Si se queda bloqueado, hay que arreglar el problema de hardware o reiniciar.
4. Qué es un proceso zombi?
Un proceso que terminó pero cuyo padre no lo recogio. Aparece como Z en ps y con corchetes alrededor del nombre.
5. Qué significa el modificador + en la columna STAT?
Que el proceso esta en el grupo de procesos en primer plano de su terminal.
6. Qué es WCHAN?
La columna WCHAN (wait channel) muestra en que función del núcleo esta dormido un proceso bloqueado. Si el proceso esta en R, aparece un guion (-).
7. Qué muestra /proc/PID/stack?
La pila de llamadas del núcleo para ese proceso, Que permite ver exactamente en que función se bloqueo.
8. Qué es el estado t (minuscula)?
Es el estado de tracing stop: el proceso esta detenido por un depurador que usa ptrace. Es similar a T pero especifico de la depuracion.
9. Qué modificador indica que un proceso es multihilo?
La letra l (minuscula) en la columna STAT.
10. Cómo se puede observar el estado de un proceso en tiempo real?
Con watch -n 1 "ps -o pid,stat,wchan,comm -p PID" o con top.
Para prácticar
- Compila y ejecuta estados.c, y desde otra terminal observa como cambia el estado con ps -o pid,stat,wchan,comm.
- Crea un proceso zombi: escribe un programa que haga fork(), Que el hijo termine inmediatamente y que el padre no llame a wait(). Observa el zombi con ps y /proc/PID/status.
- Lanza un proceso en segúndo plano y detenlo con kill -STOP PID. Observa el estado T. Reanudalo con kill -CONT PID.
- Observa los estados de los procesos de tu sistema con ps -e -o stat,comm | sort | uniq -c.
- Ejecuta un comando que haga E/S de disco intensiva y observa sí aparece en estado D.
- Usa cat /proc/PID/stack en un proceso dormido para ver la pila del núcleo.