Señales y cómo terminar procesos en GNU/Linux
Hablaremos sobre cómo identificar procesos en sistemas Linux, y cómo terminar su ejecución utilizando las señales del sistema como envío de notificaciones asincrónicas.
Hemos visto en otros posts cómo ver la lista de procesos y su información relacionada y hemos analizado sus estados y prioridades. En este artículo hablaremos sobre la administración básica de los procesos en el sistema, utilizando algunas herramientas útiles de Linux.
Identificando procesos
Los procesos en el sistema operativo están unívocamente identificados mediante un PID, o Process Identifier. El PID es un número entero que identifica a cada uno de los procesos del sistema, de una manera a la que Linux nos tiene acostumbrados, puesto que casi todos los elementos del sistema se identifican numéricamente (procesos, archivos, directorios, dispositivos, etc.).
¿Cómo podemos ver el PID de un proceso? Podemos verlo de varias maneras. Una de ellas es utilizando el comando ps como analizamos en el artículo anterior.
Analicemos la siguiente captura:
[die@debian ~]$ ps fax
PID TTY STAT TIME COMMAND
[...]
3194 ? S 0:00 /usr/sbin/cups-browsed
3319 ? Ss 0:00 /usr/sbin/cupsd -C /etc/cups/cupsd.conf
3384 tty1 Ss 0:00 /bin/login --
3572 tty1 S+ 0:00 _ -bash
3676 tty1 S+ 0:00 _ xinit /home/die/.xinitrc -- /etc/X11/xinit/xs
3677 tty7 Ss+ 4:03 _ /usr/bin/X -nolisten tcp :0 -auth /tmp/se
3690 tty1 S 0:00 _ ck-launch-session dbus-launch startlxde
3698 tty1 Sl 0:00 _ /usr/bin/lxsession -s LXDE -e LXDE
3717 tty1 S 0:08 _ openbox --config-file /home/die/.
3722 tty1 Sl 0:20 _ lxpanel --profile LXDE
3723 tty1 Sl 0:04 _ pcmanfm --desktop --profile LXDE
3724 tty1 S 0:01 _ xscreensaver -no-splash
3385 tty2 Ss+ 0:00 /sbin/getty 38400 tty2
3386 tty3 Ss+ 0:00 /sbin/getty 38400 tty3
3387 tty4 Ss+ 0:00 /sbin/getty 38400 tty4
Aquí la primer columna representa el PID del proceso, y puede verse en su encabezado.
Las opciones utilizadas son:
-f
para el «full format», es decir, vemos varias columnas con información extra sobre los procesos.-a
para ver todos los procesos excepto los líderes de sesión, y todos aquellos procesos no asociados a terminales.-x
para no mostrar los procesos con restricción a la terminal tty actual.
También con el comando pstree
y la opción «-p
» podremos ver el mismo dato en un modo de árbol de relaciones de procesos.
La muerte de un proceso con señales
Así como los procesos están «vivos» en el sistema, y representan una instancia de un programa en ejecución, un proceso termina con lo que, en la jerga, se denomina «su muerte«.
Un proceso puede terminar normalmente, o puede terminar de manera abrupta o anormal.
Una terminación normal del proceso implicaría que termina su procesamiento de manera inalterada, cumple su funcionalidad, y luego libera sus recursos y desaparece del sistema.
Cuando decimos que desaparece, estamos hablando de que su PID ya no se ve en ningún listado, y esto es debido a que el PID de un proceso y toda su información se almacenan en una tabla de procesos administrada por el kernel.
Esta tabla de procesos contiene una entrada o registro por proceso en ejecución, y es mantenida en memoria por el gestor de procesos del núcleo del sistema operativo.
Cuando un proceso «muere», su entrada en la tabla desaparece, y su espacio será ocupado por otro proceso dependiendo de la ejecución del sistema.
Como dato curioso, veamos las siguientes capturas:
[die@debian ~]$ ps fax|grep ps fax| grep -v grep
14139 pts/0 R+ 0:00 _ ps fax
[die@debian ~]$ ps fax|grep ps fax| grep -v grep
14145 pts/0 R+ 0:00 _ ps fax
El comando es simplemente un ps
ejecutado, a cuya salida filtramos para mostrar solamente la línea del propio comando ps
en la lista de procesos muestreada.
¿Qué conclusión sacamos de ejecutar este comando dos veces?
El proceso ps primero se ejecuta usando un PID determinado, 14139 en este caso, luego termina, y vuelve el control al prompt, nuestra línea de comandos. La segunda ejecución, el comando ps tiene un segundo PID, 14145, puesto que es un proceso que realiza la misma tarea, pero es un proceso totalmente distinto para el sistema.
Aquí podemos apreciar la ejecución de un proceso, su inicio, ejecución, y terminación.
Procesos y señales
A veces en el sistema operativo ejecutamos procesos que terminan sin responder, y al no terminar de manera natural, debemos terminarlos de una forma forzosa.
En Linux ésto se lleva a cabo utilizando un mecanismo de comunicación entre procesos (IPC por sus siglas en inglés) conocido como envío de señales. Aunque estrictamente no es un mecanismo de IPC del núcleo, sí permite la comunicación entre procesos, y me gusta anexarlo al término 🙂
Las señales es notificaciones o eventos asincrónicos que un proceso le envía a otro. El proceso receptor puede realizar varias tareas con una señal que recibe. Básicamente, dependiendo de la configuración de señales que tengamos en el proceso en cuestión, las acciones a tomar son tres:
- Ignorar la señal, el proceso no hará nada con la señal que reciba. Por supuesto, algunas señales como la «9» (SIGKILL) no pueden ser ignoradas.
- Realizar la acción por defecto, es decir, las acciones predeterminadas que el sistema le otorga a cada señal.
- Realizar una acción particular, programada por el programador del programa que dio origen al proceso.
Para poder ver la lista de señales que un proceso puede enviarle a otro, podemos usar el comando kill de la siguiente forma:
Cada señal es un número, y un proceso, mediante utilidades como kill
o killall
en línea de comandos puede enviar una señal a otro proceso.
Estas utilidades, por supuesto, tienen su equivalente en funciones de la interfaz de llamadas al sistema (SysCall POSIX.1), que mencionábamos en Arquitectura de GNU/Linux y en Arquitectura de sistemas *nix.
De esta lista de señales, las que nos interesan ahora son TERM (15) y KILL (9). Ambas son señales que un proceso puede enviar a otro para terminarlo.
TERM implica una terminación normal del proceso, es una especie de «solicitud» de terminación de un proceso a otro. TERM puede ser ignorada, o puede ser configurada, por el proceso receptor, para realizar cualquier otra tarea, en vez de su terminación natural.
KILL por su parte, es una señal que un proceso le envía a otro para forzar su terminación. KILL no puede ser ignorada, y por consiguiente, el proceso receptor va a terminar su ejecución en forma abrupta.
A veces alguna tarea que estamos ejecutando produce algún fallo, y deja de responder a los intentos de cierre o terminación normales, y la única manera que tenemos de terminarla, es «matándola» usando la señal KILL.
Terminando procesos por consola
Imaginemos que tenemos un proceso que deseamos terminar, por ejemplo, lancemos un proceso en segundo plano, como el siguiente:
[die@debian ~]$ yes > /dev/null &
[1] 16207
El proceso comando «yes» solamente muestra por salida estándar letras ‘y’ por default. Esta salida la estamos reenviando al dispositivo nulo para que no inunde nuestra terminal, y con el ‘&’ del final logramos que todo el proceso corra en segundo plano, de modo que nos quede la terminal para poder seguir trabajando en el prompt.
Para poder comprobar que el procesos está corriendo en segundo plano, podríamos listarlo usando:
[die@debian ~]$ ps fax |grep yes
16207 pts/0 R 0:06 _ yes
Vemos que en mi caso particular, el PID del proceso yes es 16207.
Podemos intentar terminar al proceso enviándole una señal de terminación normal TERM de la siguiente forma:
[die@debian ~]$ kill -TERM 16207
El comando kill recibe como argumento el número de señal, o la macro que lo representa. En este caso, dicho comando es equivalente a:
[die@debian ~]$ kill -15 16207
En cualquier caso, veamos ahora el estado del proceso yes corriendo:
[die@debian ~]$ ps fax |grep yes
[1]+ Terminated yes > /dev/null
Como apreciamos, el proceso terminó normalmente. yes terminó puesto que su comportamiento normal al recibir la señal de terminación TERM es, precisamente, terminar, y lo lleva a cabo.
En el caso de que dicho proceso no hubiese terminado, ya sea porque está ignorando la señal de terminación TERM, o porque simplemente no responde el proceso, podremos forzar su terminación usando una señal KILL, o 9. Veamos el mismo ejemplo probado ahora con la señal KILL:
[die@debian ~]$ yes > /dev/null &[1] 16469
[die@debian ~]$ ps fax |grep yes
16469 pts/0 R 0:03 _ yes
[die@debian ~]$
[die@debian ~]$ kill -KILL 16469
[die@debian ~]$
[die@debian ~]$ ps fax |grep yes
16490 pts/0 S+ 0:00 _ grep yes
[1]+ Killed yes > /dev/null
Aquí podremos ver que el proceso no terminó, sino que fue «muerto» por otro proceso, precisamente, nuestro proceso lanzado por el comando kill, que le envió una señal de terminación abrupta.
Quieres terminar varios procesos a la vez?
Muchas veces nos encontramos con que un programa tiene múltiples instancias en ejecución, o simplemente deseamos terminar un proceso por su nombre y no por su PID.
Para estos dos casos, podemos utilizar el nombre del proceso y el comando killall
con la misma sintaxis que el comando kill.
Supongamos que tenemos un servidor web Apache2 corriendo en nuestra máquina, y por alguna razón, deseamos terminar sus procesos.
Veamos una salida del comando ps que nos muestra los procesos que está ejecutando el servidor:
die@tuta2:~$ ps fax|grep apache
16695 pts/0 S+ 0:00 _ grep apache
15232 ? Ss 0:00 /usr/sbin/apache2 -k start
16364 ? S 0:01 _ /usr/sbin/apache2 -k start
16441 ? S 0:00 _ /usr/sbin/apache2 -k start
16674 ? S 0:00 _ /usr/sbin/apache2 -k start
16675 ? S 0:00 _ /usr/sbin/apache2 -k start
16680 ? S 0:00 _ /usr/sbin/apache2 -k start
16681 ? S 0:00 _ /usr/sbin/apache2 -k start
16682 ? S 0:00 _ /usr/sbin/apache2 -k start
16684 ? S 0:00 _ /usr/sbin/apache2 -k start
16685 ? S 0:00 _ /usr/sbin/apache2 -k start
16686 ? S 0:00 _ /usr/sbin/apache2 -k start
En este caso podríamos matar proceso por proceso, o terminarlos a todos juntos utilizando su nombre en común, y el comando killall, de esta forma:
die@tuta2:~$ killall apache2
Si por alguna razón este comando no terminara los procesos porque los mismos están ignorando la señal TERM, podremos enviarle KILL de igual manera que antes:
die@tuta2:~$ killall -KILL apache2
# o
die@tuta2:~$ killall -9 apache2
Uso de top y htop para terminar procesos
Sí, también podemos usar htop, o su predecesor, top, para terminar un proceso determinado. En htop solo será cuestión de moverse hasta el proceso que deseamos terminar, ya sea con las teclas de cursor, o con el puntero del mouse en el caso de estar trabajando en un entorno gráfico, luego presionar la tecla F9 (Kill) o ‘k’, y seleccionar la señal a enviar (por default, SIGTERM o 15). Con Enter enviamos la señal al proceso, y éste reaccionará a la misma.
En top cambia un poco el mecanismo. Deberemos presionar la tecla ‘k’ para poder introducir el PID del proceso que deseamos terminar, y luego deberemos introducir el numero de señal a enviar, por defecto, 15. Al presionar Enter enviaremos la señal al proceso
Conclusiones
Hemos hablado sobre terminación de procesos, una de las tareas propias de la administración de procesos. Los estados de los procesos, las prioridades de ejecución, los cambios de prioridades y su administración, pueden ampliarse en Procesos en Linux, estados y prioridades
Por otro lado, para los entusiastas de la programación en C, pueden leer un artículo que escribí sobre los mecanismos de comunicación entre procesos en sistemas *nix, entre los que se incluyen las señales: IPC: Comunicación entre procesos en *nix
¡Espero les sirva!
3 comentarios
fraciel arevalo · 5 septiembre, 2016 a las 19:54
Muy interesante deceo visualizar los vídeos
Diego Córdoba · 5 septiembre, 2016 a las 20:24
Hola Fraciel! A qué videos te referís? Así te los paso.
Slds!
fracielarevalo · 5 septiembre, 2016 a las 22:01
muy interesante
Los comentarios están cerrados.