¿Cómo se relaciona SIGINT con las otras señales de terminación como SIGTERM, SIGQUIT y SIGKILL?

103

En los sistemas POSIX, las señales de terminación suelen tener el siguiente orden (según muchas páginas MAN y las especificaciones POSIX):

  1. SIGTERM: solicite cortésmente que finalice el proceso. Terminará elegantemente, limpiando todos los recursos (archivos, sockets, procesos secundarios, etc.), eliminando archivos temporales, etc.

  2. SIGQUIT - solicitud más contundente. Terminará sin gracia, aún limpiando recursos que absolutamente necesitan limpieza, pero tal vez no elimine archivos temporales, tal vez escriba información de depuración en alguna parte; en algunos sistemas también se escribirá un volcado del núcleo (independientemente de si la aplicación capta la señal o no).

  3. SIGKILL - petición más contundente. Ni siquiera se le pide al proceso que haga nada, pero el sistema limpiará el proceso, le guste o no. Lo más probable es que se escriba un volcado de memoria.

¿Cómo encaja SIGINT en esa imagen? Un proceso CLI generalmente es terminado por SIGINT cuando el usuario presiona CRTL + C, sin embargo, un proceso en segundo plano también puede ser terminado por SIGINT usando la utilidad KILL. Lo que no puedo ver en las especificaciones o los archivos de encabezado es si SIGINT es más o menos contundente que SIGTERM o si existe alguna diferencia entre SIGINT y SIGTERM.

ACTUALIZAR:

La mejor descripción de las señales de terminación que encontré hasta ahora está en la documentación GNU LibC . Explica muy bien que existe una diferencia intencionada entre SIGTERM y SIGQUIT.

Dice sobre SIGTERM:

Es la forma normal de pedir cortésmente a un programa que termine.

Y dice sobre SIGQUIT:

[...] y produce un volcado del núcleo cuando finaliza el proceso, al igual que una señal de error de programa. Puede pensar en esto como una condición de error de programa "detectada" por el usuario. [...] Es mejor omitir ciertos tipos de limpieza al manejar SIGQUIT. Por ejemplo, si el programa crea archivos temporales, debería manejar las otras solicitudes de terminación borrando los archivos temporales. Pero es mejor que SIGQUIT no los elimine, para que el usuario pueda examinarlos junto con el volcado de memoria.

Y SIGHUP también se explica bastante bien. SIGHUP no es realmente una señal de terminación, solo significa que la "conexión" con el usuario se ha perdido, por lo que la aplicación no puede esperar que el usuario lea más salida (por ejemplo, salida stdout / stderr) y no hay entrada que esperar del usuario por más tiempo. Para la mayoría de las aplicaciones, eso significa que es mejor que salgan. En teoría, una aplicación también podría decidir que entra en modo demonio cuando se recibe un SIGHUP y ahora se ejecuta como un proceso en segundo plano, escribiendo la salida en un archivo de registro configurado. Para la mayoría de los demonios que ya se ejecutan en segundo plano, SIGHUP generalmente significa que deben volver a examinar sus archivos de configuración, por lo que los envía a los procesos en segundo plano después de editar los archivos de configuración.

Sin embargo, no hay una explicación útil de SIGINT en esta página, aparte de que es enviado por CRTL + C. ¿Hay alguna razón por la que uno maneje SIGINT de una manera diferente a SIGTERM? Si es así, ¿cuál sería la razón y cómo sería diferente el manejo?

Mecki
fuente
1
Buena pregunta. Sospecho que algo del histórico Unix cruft estaría involucrado en la respuesta.
Alex B
Sé que esta pregunta es antigua, pero en caso de que alguien viniera aquí para obtener una lista extensa de señales para su sistema operativo (Linux), puede encontrarlas escribiendo sudo fuser -len el símbolo del sistema. Para mí esto trae a colación:HUP INT QUIT ILL TRAP ABRT IOT BUS FPE KILL USR1 SEGV USR2 PIPE ALRM TERM STKFLT CHLD CONT STOP TSTP TTIN TTOU URG XCPU XFSZ VTALRM PROF WINCH IO PWR SYS UNUSED
Nick Bull
3
También intente kill -lobtener una lista de señales.
AAAfarmclub

Respuestas:

88

SIGTERM y SIGKILL están destinados a solicitudes de "terminar este proceso" de propósito general. SIGTERM (por defecto) y SIGKILL (siempre) causarán la terminación del proceso. SIGTERM puede ser detectado por el proceso (por ejemplo, para que pueda hacer su propia limpieza si así lo desea), o incluso ignorado por completo; pero SIGKILL no puede ser capturado ni ignorado.

SIGINT y SIGQUIT están diseñados específicamente para solicitudes del terminal: se pueden asignar caracteres de entrada particulares para generar estas señales (dependiendo de la configuración de control del terminal). La acción predeterminada para SIGINT es el mismo tipo de terminación de proceso que la acción predeterminada para SIGTERM y la acción inmutable para SIGKILL; la acción predeterminada para SIGQUIT es también la terminación del proceso, pero pueden ocurrir acciones adicionales definidas por la implementación, como la generación de un volcado de memoria. Cualquiera puede ser detectado o ignorado por el proceso si es necesario.

SIGHUP, como usted dice, está destinado a indicar que la conexión del terminal se ha perdido, en lugar de ser una señal de terminación como tal. Pero, nuevamente, la acción predeterminada para SIGHUP (si el proceso no lo detecta o lo ignora) es terminar el proceso de la misma manera que SIGTERM, etc.

Hay una tabla en las definiciones POSIX para la signal.hque se enumeran las diversas señales y sus acciones y propósitos predeterminados, y el capítulo Interfaz de terminal general incluye muchos más detalles sobre las señales relacionadas con el terminal.

Matthew Slattery
fuente
10
Este es el punto clave: SIGINT y SIGQUIT se pueden generar desde el terminal usando caracteres individuales, mientras el programa se está ejecutando. Las otras señales tienen que ser generadas por otro programa, de alguna manera (por ejemplo, por el comando kill). SIGINT es menos violento que SIGQUIT; este último produce un volcado de núcleo. SIGKILL no puede quedar atrapado. SIGHUP se genera si su conexión se cuelga (la ventana se cierra, etc.). Entonces, todos tienen diferentes significados.
Jonathan Leffler
TTY Demystified tiene información fácilmente digerible sobre cómo interactúan las señales con el subsistema tty del kernel. Agrega algo de contexto a su respuesta.
Daniel Näslund
2
Parece que las especificaciones no son muy precisas, pero tengo entendido que SIgint le pide al programa que detenga su acción actual, no necesariamente que se cierre. Para un programa diseñado solo hacer una acción por ejecución que implica salir, pero para un programa interactivo que tiene algún tipo de bucle de lectura-evaluación-impresión, puede significar renunciar a la evaluación actual y volver a leer la entrada del usuario. Creo que menos hace eso en sigint.
bdsl
¿Qué señal se envía durante el reinicio?
Dan Dascalescu
10

Como señaló DarkDust, muchas señales tienen los mismos resultados, pero los procesos pueden asociarles diferentes acciones al distinguir cómo se genera cada señal. Mirando el código fuente del kernel de FreeBSD (kern_sig.c) veo que las dos señales se manejan de la misma manera, terminan el proceso y se envían a cualquier hilo.

SA_KILL|SA_PROC,             /* SIGINT */
SA_KILL|SA_PROC,             /* SIGTERM */
Diomidis Spinellis
fuente
9

man 7 signal

Esta es la conveniente página de manual no normativa del proyecto de páginas de manual de Linux que a menudo desea consultar para obtener información sobre señales de Linux.

La versión 3.22 menciona cosas interesantes como:

Las señales SIGKILL y SIGSTOP no se pueden capturar, bloquear ni ignorar.

y contiene la tabla:

Signal     Value     Action   Comment
----------------------------------------------------------------------
SIGHUP        1       Term    Hangup detected on controlling terminal
                              or death of controlling process
SIGINT        2       Term    Interrupt from keyboard
SIGQUIT       3       Core    Quit from keyboard
SIGILL        4       Core    Illegal Instruction
SIGABRT       6       Core    Abort signal from abort(3)
SIGFPE        8       Core    Floating point exception
SIGKILL       9       Term    Kill signal
SIGSEGV      11       Core    Invalid memory reference
SIGPIPE      13       Term    Broken pipe: write to pipe with no
                              readers
SIGALRM      14       Term    Timer signal from alarm(2)
SIGTERM      15       Term    Termination signal
SIGUSR1   30,10,16    Term    User-defined signal 1
SIGUSR2   31,12,17    Term    User-defined signal 2
SIGCHLD   20,17,18    Ign     Child stopped or terminated
SIGCONT   19,18,25    Cont    Continue if stopped
SIGSTOP   17,19,23    Stop    Stop process
SIGTSTP   18,20,24    Stop    Stop typed at tty
SIGTTIN   21,21,26    Stop    tty input for background process
SIGTTOU   22,22,27    Stop    tty output for background process

que resume la señal Actionque distingue, por ejemplo, SIGQUIT de SIGQUIT, ya que SIGQUIT tiene acción Corey SIGINT Term.

Las acciones están documentadas en el mismo documento:

The entries in the "Action" column of the tables below specify the default disposition for each signal, as follows:

Term   Default action is to terminate the process.

Ign    Default action is to ignore the signal.
Core   Default action is to terminate the process and dump core (see core(5)).
Stop   Default action is to stop the process.
Cont   Default action is to continue the process if it is currently stopped.

No puedo ver ninguna diferencia entre SIGTERM y SIGINT desde el punto de vista del kernel ya que ambos tienen acción Termy ambos pueden ser capturados. Parece que es solo una "distinción de convención de uso común":

  • SIGINT es lo que sucede cuando haces CTRL-C desde la terminal
  • SIGTERM es la señal predeterminada enviada por kill

Algunas señales son ANSI C y otras no

Una diferencia considerable es que:

  • SIGINT y SIGTERM son ANSI C, por lo que son más portátiles
  • SIGQUIT y SIGKILL no son

Se describen en el apartado "7.14 Manejo de señales" del borrador C99 N1256 :

  • Recepción SIGINT de una señal de atención interactiva
  • SIGTERM una solicitud de terminación enviada al programa

lo que hace que SIGINT sea un buen candidato para un Ctrl + C interactivo.

POSIX 7

POSIX 7 documenta las señales con el signal.hencabezado: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html

Esta página también tiene la siguiente tabla de interés que menciona algunas de las cosas que ya habíamos visto man 7 signal:

Signal    Default Action   Description
SIGABRT   A                Process abort signal.
SIGALRM   T                Alarm clock.
SIGBUS    A                Access to an undefined portion of a memory object.
SIGCHLD   I                Child process terminated, stopped,
SIGCONT   C                Continue executing, if stopped.
SIGFPE    A                Erroneous arithmetic operation.
SIGHUP    T                Hangup.
SIGILL    A                Illegal instruction.
SIGINT    T                Terminal interrupt signal.
SIGKILL   T                Kill (cannot be caught or ignored).
SIGPIPE   T                Write on a pipe with no one to read it.
SIGQUIT   A                Terminal quit signal.
SIGSEGV   A                Invalid memory reference.
SIGSTOP   S                Stop executing (cannot be caught or ignored).
SIGTERM   T                Termination signal.
SIGTSTP   S                Terminal stop signal.
SIGTTIN   S                Background process attempting read.
SIGTTOU   S                Background process attempting write.
SIGUSR1   T                User-defined signal 1.
SIGUSR2   T                User-defined signal 2.
SIGTRAP   A                Trace/breakpoint trap.
SIGURG    I                High bandwidth data is available at a socket.
SIGXCPU   A                CPU time limit exceeded.
SIGXFSZ   A                File size limit exceeded.

BusyBox init

El comando predeterminado 1.29.2 de BusyBox rebootenvía un SIGTERM a los procesos, duerme por un segundo y luego envía SIGKILL. Esta parece ser una convención común en diferentes distribuciones.

Cuando apaga un sistema BusyBox con:

reboot

envía una señal al proceso de inicio.

Entonces, el manejador de señales init termina llamando:

static void run_shutdown_and_kill_processes(void)
{
    /* Run everything to be run at "shutdown".  This is done _prior_
     * to killing everything, in case people wish to use scripts to
     * shut things down gracefully... */
    run_actions(SHUTDOWN);

    message(L_CONSOLE | L_LOG, "The system is going down NOW!");

    /* Send signals to every process _except_ pid 1 */
    kill(-1, SIGTERM);
    message(L_CONSOLE, "Sent SIG%s to all processes", "TERM");
    sync();
    sleep(1);

    kill(-1, SIGKILL);
    message(L_CONSOLE, "Sent SIG%s to all processes", "KILL");
    sync();
    /*sleep(1); - callers take care about making a pause */
}

que imprime en la terminal:

The system is going down NOW!
Sent SIGTERM to all processes
Sent SIGKILL to all processes

Aquí hay un ejemplo concreto mínimo de eso .

Señales enviadas por el kernel

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
fuente
8

Después de una búsqueda rápida en Google de sigint vs sigterm , parece que la única diferencia intencionada entre los dos es si se inició mediante un método abreviado de teclado o mediante una llamada explícita a kill.

Como resultado, podría, por ejemplo, interceptar sigint y hacer algo especial con él, sabiendo que probablemente fue enviado por un atajo de teclado. Quizás actualice la pantalla o algo, en lugar de morir (no recomendado, ya que la gente espera ^Cmatar el programa, solo un ejemplo).

También aprendí que ^\debería enviar sigquit, que puedo comenzar a usar yo mismo. Parece muy útil.

Jonathan
fuente
3

Usando kill(tanto la llamada al sistema como la utilidad`, puede enviar casi cualquier señal a cualquier proceso, siempre que tenga el permiso. Un proceso no puede distinguir cómo una señal cobró vida y quién la envió.

Dicho esto, SIGINT realmente está destinado a señalar la interrupción Ctrl-C, mientras que SIGTERM es la señal de terminal general. No existe el concepto de que una señal sea "más contundente", con la única excepción de que hay señales que no se pueden bloquear ni manejar (SIGKILL y SIGSTOP, según la página de manual).

Una señal solo puede ser "más contundente" que otra señal con respecto a cómo un proceso de recepción maneja la señal (y cuál es la acción predeterminada para esa señal). Por ejemplo, de forma predeterminada, tanto SIGTERM como SIGINT conducen a la terminación. Pero si ignora SIGTERM, no terminará su proceso, mientras que SIGINT todavía lo hace.

DarkDust
fuente
0

Con la excepción de algunas señales, los manejadores de señales pueden captar las diversas señales, o se puede modificar el comportamiento predeterminado al recibir una señal. Consulte la signal(7)página del manual para obtener más detalles.

Ignacio Vázquez-Abrams
fuente
Sí, pero si no conozco "el significado" de un single, captar la señal no tiene sentido, porque no sabré qué hacer en mi aplicación. GNU C, por ejemplo, explica la diferencia entre SIGQUIT y SIGTERM. Pero brinda poca información sobre SIGINT: gnu.org/s/libc/manual/html_node/Termination-Signals.html
Mecki
"La SIGINTseñal (“ interrupción del programa ”) se envía cuando el usuario escribe el carácter INTR (normalmente C-c)". "SIGINT 2 Term Interrupt from keyboard" Presiona Ctrl-C, SIGINTse envía. El proceso normalmente muere. ¿Qué más dar?
Ignacio Vazquez-Abrams
Potencialmente, podría haber una descripción de la intención que el programador debería asumir que tendrá el usuario cuando presione ctrl-c, es decir, la semántica del mensaje. Como ejemplo, la especificación HTTP deja en claro que cuando un usuario envía una solicitud GET, el servidor no debe asumir que desea que haga algo más que enviar una respuesta.
bdsl