1. Qué son los grupos de procesos
Un grupo de procesos es un conjunto de procesos relacionados que se tratan como una unidad para el control de la terminal y la entrega de senales. Cada proceso pertenece a un grupo de procesos, identificado por un PGID (process group ID). El proceso que crea el grupo es el lider del grupo, y su PID es el PGID.
Los grupos de procesos se usan para el job control: la shell agrupa los procesos de un comando (y sus hijos) en un grupo, para poder enviarles senales juntos (por ejemplo, Ctrl+C envia SIGINT a todo el grupo).
Cuando se crea un proceso con fork, hereda el grupo de procesos del padre. Se puede cambiar de grupo con setpgid() o setpgrp().
2. La terminal de control
Cada sesion puede tener (o no) una terminal de control. La terminal de control es el dispositivo (por ejemplo, /dev/pts/0) Que recibe la entrada del teclado y muestra la salida.
Cuando un proceso lee de la terminal, recibe la entrada del teclado. Cuando escribe en la terminal, muestra la salida. La terminal de control se asigna a la sesion cuándo el lider de sesion abre un dispositivo de terminal.
Solo el grupo de procesos en primer plano (foreground) puede leer de la terminal. Si un proceso en segúndo plano intenta leer, recibe SIGTTIN y se detiene. Si intenta escribir (con tostop activado), recibe SIGTTOU.
| Situacion | Senal | Que pasa |
|---|---|---|
| Proceso en segúndo plano lee de la terminal | SIGTTIN | Se detiene (estado T). |
| Proceso en segúndo plano escribe en la terminal (con tostop) | SIGTTOU | Se detiene (estado T). |
| Ctrl+C en la terminal | SIGINT | Se envia al grupo en primer plano. |
| Ctrl+Z en la terminal | SIGTSTP | Se envia al grupo en primer plano. |
3. Senales y grupos de procesos
Las senales de la terminal (SIGINT, SIGTSTP, SIGQUIT) se envian a todo el grupo de procesos en primer plano, no sólo al proceso que esta ejecutandose. Esto permite que todos los procesos de un comando (y sus hijos) reciban la senal.
Por ejemplo, Sí ejecutas find / | grep foo (Que crea dos procesos: find y grep), y presionas ctrl+C, ambos procesos reciben SIGINT y terminan. Esto es porque ambos estan en el mismo grupo de procesos.
La shell gestiona los grupos de procesos:
- Cuando lanzas un comando en primer plano: la shell crea un grupo de procesos para el comando, lo pone en primer plano (tcsetpgrp), y espera.
- Cuando lanzas un comando en segúndo plano (con &): la shell crea un grupo de procesos, pero no lo pone en primer plano. El comando se ejecuta en segúndo plano.
- Con fg: la shell pone el grupo en primer plano y envia SIGCONT.
- Con bg: la shell envia SIGCONT al grupo en segúndo plano.
4. Qué es una sesion
Una sesion es un conjunto de grupos de procesos. La sesion se identifica por un SID (session ID), Que es el PID del lider de sesion. Una sesion puede tener (o no) una terminal de control.
Las sesiones se usan para agrupar procesos relacionados: todos los procesos de una sesion de terminal (la shell y sus hijos) pertenecen a la misma sesion. Cuando el usuario cierra la sesion (logout), todos los procesos de la sesion reciben SIGHUP y terminan (a menos que se desvinculen).
La sesion es la unidad de control de la terminal: la terminal de control pertenece a la sesion, y todos los grupos de procesos de la sesion pueden acceder a ella (Según esten en primer o segúndo plano).
Cuando se crea un proceso con fork, hereda la sesion del padre. Se puede crear una nueva sesion con setsid().
5. setsid: crear una nueva sesion
setsid() crea una nueva sesion y convierte al proceso en lider de sesion. El proceso se desvincula de su sesion anterior y de su terminal de control.
#include
pid_t setsid(void);
setsid hace tres cosas:
- Crea una nueva sesion: el proceso se convierte en el lider de la nueva sesion. El SID es el PID del proceso.
- Crea un nuevo grupo de procesos: el proceso se convierte en el lider del nuevo grupo. El PGID es el PID del proceso.
- Desvincula la terminal de control: el proceso pierde su terminal de control (Sí tenia una).
setsid sólo puede ser llamado por un proceso que no sea lider de grupo. Si el proceso ya es lider de grupo, setsid falla con EPERM. Por eso, se usa junto con fork: el hijo (Que no es lider de grupo) llama a setsid.
setsid es lo que permite a un proceso desvincularse de la terminal y convertirse en demonio. Sin setsid, el proceso seguiria vinculado a la terminal de su padre y recibiria senales de ella.
6. El lider de sesion
El lider de sesion es el proceso que creó la sesion (con setsid). Su PID es el SID de la sesion. El lider de sesion tiene propiedades especiales:
- Puede adquirir una terminal de control: abriendo un dispositivo de terminal, el lider de sesion lo asigna como terminal de control de la sesion.
- Si el lider termina, la sesion se destruye: todos los procesos de la sesion reciben SIGHUP y la terminal de control se desvincula.
- No puede ser lider de grupo de otra sesion: el lider de sesion pertenece a su propio grupo.
Por eso, en la creacion de demonios, se usa el doble fork: el primer hijo llama a setsid (se convierte en lider de sesion), y el segúndo fork crea un proceso que no es lider de sesion. El demonio (el nieto) no puede adquirir una terminal de control, lo que es deseable.
7. La terminal de control
La terminal de control es el dispositivo de terminal asociado a una sesion. Es la terminal dónde el usuario interactua con la shell.
La terminal de control se asigna cuándo el lider de sesion abre un dispositivo de terminal (por ejemplo, /dev/tty1 o /dev/pts/0). El núcleo asocia la terminal a la sesion.
La terminal de control tiene dos grupos de procesos asociados:
- Grupo en primer plano: el grupo que puede leer y escribir en la terminal. Recibe las senales de la terminal (SIGINT, SIGTSTP).
- Grupos en segúndo plano: los grupos que no pueden leer de la terminal (reciben SIGTTIN Sí intentan).
La shell gestiona los grupos en primer y segúndo plano con tcsetpgrp() y tcgetpgrp().
Cuando la terminal se cierra (el usuario hace logout), el núcleo envia SIGHUP a todos los procesos de la sesion. Los procesos que capturan SIGHUP y hacen limpieza pueden terminar ordenadamente. Los que no lo capturan terminan.
SIGHUP (senal 1) se envia a todos los procesos de una sesion cuándo la terminal se cierra. Los demonios capturan SIGHUP y la usan para recargar su configuración (en lugar de terminar). Por eso, "hangup" (colgar) se convirtio en "recargar configuración" para los demonios.
8. Cómo se convierte un programa en un servicio
Un servicio (o demonio) es un programa que se ejecuta en segúndo plano, Sin terminal de control, y proporciona un servicio al sistema. La conversion de un programa en servicio implica:
- Doble fork + setsid: desvincularse de la terminal y del padre.
- Cambiar de directorio: tipicamente a /, para no bloquear el desmontaje de sistemás de archivos.
- Cerrar descriptores: cerrar stdin, stdout, stderr y redirigirlos a /dev/null.
- Cambiar de usuario: bajar privilegios sí se ejecuto como root.
- Crear un archivo PID: guardar el PID en un archivo (por ejemplo, /var/run/mi_servicio.pid) para que el sistema pueda gestionarlo.
- Manejar senales: capturar SIGHUP para recargar configuración, SIGTERM para terminar ordenadamente.
En sistemás modernos, systemd gestiona los servicios y proporciona muchas de estas funciónalidades (reinicio automatico, logging, etc.). El programa sólo necesita ejecutarse en primer plano, y systemd lo convierte en servicio.
9. systemd y los servicios
systemd es el sistema de init y gestor de servicios de la mayoria de las distribuciones linux modernas. Reemplaza al sistema de init tradicional (SysV init) y gestiona los servicios de forma más eficiente.
systemd ofrece varias ventajas sobre el init tradicional:
- Inicio paralelo: los servicios se inician en paralelo, no secuencialmente.
- Dependencias: los servicios pueden declarar dependencias (After, Requires, Wants).
- Supervision: systemd monitorea los servicios y los reinicia sí fallan.
- Logging: systemd captura la salida de los servicios (stdout/stderr) y la envia a journald.
- Sockets: systemd puede crear sockets y pasarlos a los servicios (socket activation).
- cgroups: systemd usa cgroups para aislar y limitar los servicios.
Con systemd, un servicio se define en un archivo de unidad (.service):
$ cat /etc/systemd/system/mi_servicio.service
[Unit]
Description=Mi servicio
After=network.target
[Service]
Type=Simple
Execstart=/usr/bin/mi_servicio
Restart=on-failure
User=mi_usuario
Group=mi_grupo
Tasksmax=100
[Install]
Wantedby=multi-user.target
Con Type=Simple, systemd ejecuta el programa en primer plano y lo supervisa. No se necesita doble fork ni setsid: systemd se encarga de todo. El programa sólo necesita ejecutarse y manejar SIGTERM para terminar ordenadamente.
Los comandos basicos de systemd son:
$ systemctl start mi_servicio # iniciar
$ systemctl stop mi_servicio # detener (envia SIGTERM)
$ systemctl restart mi_servicio # reiniciar
$ systemctl status mi_servicio # ver estado
$ systemctl enable mi_servicio # habilitar al arranque
$ systemctl disable mi_servicio # deshabilitar al arranque
$ journalctl -u mi_servicio # ver logs
10. Observar grupos y sesiones en /proc
Los grupos y sesiones de un proceso se exponen en /proc:
| Archivo/Campo | Que muestra |
|---|---|
| /proc/PID/stat (campo 5) | pgid: process group ID. |
| /proc/PID/stat (campo 6) | Sid: session ID. |
| /proc/PID/stat (campo 8) | tpgid: foreground process group ID of the controlling terminal. |
| /proc/PID/stat (campo 7) | tty_nr: controlling terminal. |
$ ps -o pid,pgid,Sid,tty,comm
PID PGID SID TT COMMAND
402 402 402 pts/0 bash
500 500 402 pts/0 sleep
501 402 402 pts/0 gcc
600 600 600 ? servidor
601 600 600 ? worker
El servidor (600) y sus workers (601) tienen su propia sesion (SID 600) y no tienen terminal (TT ?). bash (402) y sus hijos (500, 501) comparten la sesion 402 y la terminal pts/0.
En /proc/PID/stat, los campos 5, 6, 7 y 8 contienen esta información en formato compacto:
$ awk '{print "pid=" $1, "pgid=" $5, "Sid=" $6, "tty=" $7, "tpgid=" $8}' /proc/self/stat
pid=448 pgid=402 Sid=402 tty=34816 tpgid=448
11. Un programa que demuestra grupos y sesiones
El siguiente programa crea un hijo, lo pone en un grupo de procesos nuevo, y muestra la información de grupos y sesiones:
#define _POSIX_C_SOURCE 200809L
#include
#include
#include
#include
static void mostrar_info(const char *Quién)
{
printf("%s: PID=%d PGID=%d SID=%d\n",
Quién, (int) getpid(), (int) getpgrp(), (int) getsid(0));
}
int main(void)
{
mostrar_info("Padre (antes)");
pid_t pid = fork();
if (pid < 0) { perror("fork"); return 1; }
if (pid == 0) {
/* Hijo: crear un nuevo grupo de procesos */
if (setpgid(0, 0) != 0) {
perror("setpgid");
_exit(1);
}
mostrar_info("Hijo (nuevo grupo)");
/* Crear una nueva sesion (Sólo sí no es lider de grupo) */
/* pid_t sid = setsid(); */
/* printf("Nueva sesion: %d\n", (int) Sid); */
sleep(2);
_exit(0);
}
/* Padre: esperar */
wait(NULL);
mostrar_info("Padre (Después)");
return 0;
}
$ gcc -std=c17 -Wall -Wextra -o grupos_Sesiones grupos_Sesiones.c
$ ./grupos_Sesiones
Padre (antes): PID=1080 PGID=1080 SID=1080
Hijo (nuevo grupo): PID=1081 PGID=1081 SID=1080
Padre (Después): PID=1080 PGID=1080 SID=1080
El hijo creó un nuevo grupo de procesos (PGID=1081), pero sigue en la misma sesion (SID=1080). El padre no se ve afectado.
12. Resumen
- Los grupos de procesos agrupan procesos para el control de la terminal y la entrega de senales.
- El PGID identifica al grupo; el lider del grupo tiene PID = PGID.
- Las sesiones agrupan grupos de procesos. El SID identifica la sesion.
- La terminal de control pertenece a la sesion y se asigna al lider.
- Solo el grupo en primer plano puede leer de la terminal.
- setsid crea una nueva sesion y desvincula la terminal.
- Los demonios usan doble fork + setsid para desvincularse.
- systemd gestiona los servicios modernos (Type=Simple).
- Los grupos y sesiones se observan en /proc/PID/stat (campos 5, 6, 7, 8).
13. Preguntas de repaso
Intenta responder cada una antes de abrir la respuesta.
1. Qué es un grupo de procesos?
Un conjunto de procesos relacionados que se tratan como una unidad para el control de la terminal y la entrega de senales. Se identifica por el PGID.
2. Qué es una sesion?
Un conjunto de grupos de procesos. Se identifica por el SID (PID del lider de sesion). Puede tener una terminal de control.
3. Qué hace setsid?
Crea una nueva sesion, crea un nuevo grupo de procesos, y desvincula la terminal de control. El proceso se convierte en lider de sesion.
4. Por que setsid falla sí el proceso ya es lider de grupo?
Porque un lider de grupo no puede crear una nueva sesion (debe ser un proceso que no sea lider de grupo). Por eso se usa fork primero.
5. Qué es la terminal de control?
El dispositivo de terminal asociado a una sesion. Es dónde el usuario interactua con la shell.
6. Qué pasa cuándo se cierra la terminal?
El núcleo envia SIGHUP a todos los procesos de la sesion. Los que no capturan SIGHUP terminan.
7. Qué es SIGHUP para los demonios?
Los demonios capturan SIGHUP y la usan para recargar su configuración, en lugar de terminar.
8. Cómo gestiona systemd los servicios?
Con archivos de unidad (.service) Que definen el comando, dependencias, reinicio automatico, usuario, limites, etc. El programa se ejecuta en primer plano y systemd lo supervisa.
9. Qué campos de /proc/PID/stat muestran grupos y sesiones?
Campo 5: pgid. Campo 6: Sid. Campo 7: tty_nr. Campo 8: tpgid.
10. Por que el doble fork en la creacion de demonios?
El primer fork desvincula del padre. setsid crea nueva sesion. El segúndo fork asegura que el demonio no sea lider de sesion (y no pueda adquirir terminal).
Para prácticar
- Compila y ejecuta grupos_Sesiones.c. Observa los PGID y SID.
- Usa ps -o pid,pgid,Sid,tty,comm para ver los grupos y sesiones de tu sistema.
- Lee los campos 5-8 de /proc/self/stat.
- Escribe un programa que se convierta en lider de sesion con setsid y verifique que se desvincula de la terminal.
- Investiga los archivos de unidad de systemd en /etc/systemd/system/.
- Usa journalctl para ver los logs de un servicio.