Señales y cómo terminar procesos en GNU/Linux

Publicado por Diego Córdoba en

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:

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.

pstree señales

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:

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:

signals señales

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.

people-315910_960_720KILL 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:

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:

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:

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:

En cualquier caso, veamos ahora el estado del proceso yes corriendo:

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:

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:

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:

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:

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.

htopkill señales

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

topkill señales

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!


Diego Córdoba

- Ingeniero en Informática - Mg. Teleinformática - Tesis pendiente - Docente universitario - Investigador