Grupos, Sesiones y demonios - Procesos e Hilos
Volver a Procesos e Hilos Bloque 6 - Zombis, huerfanos y demonios - Tema 27 de 43

Tema 27

Grupos, Sesiones y demonios

Los procesos no sólo se organizan en arboles padre-hijo. Tambien se agrupan en grupos de procesos y sesiones, Que determinan como interactuan con la terminal y como se controlan. En este tema veras que son los grupos y las sesiones, Como se crean, y como un programa se convierte en un demonio o servicio.

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().

Grupos de procesos y sesiones. Una sesion contiene varios grupos de procesos. Cada grupo tiene un lider. La terminal de control pertenece a la sesion. Sesion (SID = 402) Grupo de procesos 402 (lider: bash) bash(402) - shell interactiva sleep(500) - hijo de bash Terminal: /dev/pts/0 Grupo de procesos 500 (lider: sleep) sleep(500) - en segúndo plano Sin terminal de control Grupo de procesos 600 (lider: servidor) servidor(600) - demonio worker(601), worker(602) - hijos
Una sesion contiene varios grupos de procesos. Cada grupo tiene un lider y puede tener o no una terminal de control.

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.

SituacionSenalQue pasa
Proceso en segúndo plano lee de la terminalSIGTTINSe detiene (estado T).
Proceso en segúndo plano escribe en la terminal (con tostop)SIGTTOUSe detiene (estado T).
Ctrl+C en la terminalSIGINTSe envia al grupo en primer plano.
Ctrl+Z en la terminalSIGTSTPSe 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:

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.

C - firma de setsid

#include 

pid_t setsid(void);

setsid hace tres cosas:

  1. Crea una nueva sesion: el proceso se convierte en el lider de la nueva sesion. El SID es el PID del proceso.
  2. Crea un nuevo grupo de procesos: el proceso se convierte en el lider del nuevo grupo. El PGID es el PID del proceso.
  3. 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 la clave de los demonios

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:

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:

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: la senal de logout

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:

  1. Doble fork + setsid: desvincularse de la terminal y del padre.
  2. Cambiar de directorio: tipicamente a /, para no bloquear el desmontaje de sistemás de archivos.
  3. Cerrar descriptores: cerrar stdin, stdout, stderr y redirigirlos a /dev/null.
  4. Cambiar de usuario: bajar privilegios sí se ejecuto como root.
  5. Crear un archivo PID: guardar el PID en un archivo (por ejemplo, /var/run/mi_servicio.pid) para que el sistema pueda gestionarlo.
  6. 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:

Con systemd, un servicio se define en un archivo de unidad (.service):

terminal - archivo de unidad systemd

$ 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:

terminal - comandos de systemd

$ 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/CampoQue 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.
terminal - observar grupos y sesiones

$ 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:

terminal - leer /proc/PID/stat

$ 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:

grupos_Sesiones.c

#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;
}
terminal - ejecutar grupos_Sesiones

$ 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

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

  1. Compila y ejecuta grupos_Sesiones.c. Observa los PGID y SID.
  2. Usa ps -o pid,pgid,Sid,tty,comm para ver los grupos y sesiones de tu sistema.
  3. Lee los campos 5-8 de /proc/self/stat.
  4. Escribe un programa que se convierta en lider de sesion con setsid y verifique que se desvincula de la terminal.
  5. Investiga los archivos de unidad de systemd en /etc/systemd/system/.
  6. Usa journalctl para ver los logs de un servicio.