Quel est le rapport entre SIGINT et les autres signaux de terminaison tels que SIGTERM, SIGQUIT et SIGKILL?

103

Sur les systèmes POSIX, les signaux de terminaison ont généralement l'ordre suivant (selon de nombreuses pages MAN et les spécifications POSIX):

  1. SIGTERM - demandez poliment à un processus de se terminer. Il se terminera en douceur, nettoyant toutes les ressources (fichiers, sockets, processus enfants, etc.), supprimant les fichiers temporaires, etc.

  2. SIGQUIT - demande plus énergique. Il se terminera de manière disgracieuse, nettoyant toujours les ressources qui ont absolument besoin d'être nettoyées, mais peut-être pas supprimer les fichiers temporaires, peut-être écrire des informations de débogage quelque part; sur certains systèmes, un vidage de mémoire sera également écrit (que le signal soit capté par l'application ou non).

  3. SIGKILL - la demande la plus forte. On ne demande même pas au processus de faire quoi que ce soit, mais le système nettoiera le processus, que cela veuille ou non. Très probablement, un vidage de mémoire est écrit.

Comment SIGINT s'inscrit-il dans cette image? Un processus CLI est généralement terminé par SIGINT lorsque l'utilisateur frappe CRTL + C, cependant un processus d'arrière-plan peut également être terminé par SIGINT à l'aide de l'utilitaire KILL. Ce que je ne vois pas dans les spécifications ou les fichiers d'en-tête, c'est si SIGINT est plus ou moins puissant que SIGTERM ou s'il y a une différence entre SIGINT et SIGTERM.

METTRE À JOUR:

La meilleure description des signaux de terminaison que j'ai trouvée jusqu'à présent se trouve dans la documentation GNU LibC . Cela explique très bien qu'il existe une différence voulue entre SIGTERM et SIGQUIT.

Cela dit à propos de SIGTERM:

C'est la manière normale de demander poliment à un programme de se terminer.

Et cela dit à propos de SIGQUIT:

[...] et produit un vidage de mémoire quand il termine le processus, tout comme un signal d'erreur de programme. Vous pouvez considérer cela comme une condition d'erreur de programme «détectée» par l'utilisateur. [...] Il est préférable d'omettre certains types de nettoyages lors de la gestion de SIGQUIT. Par exemple, si le programme crée des fichiers temporaires, il doit gérer les autres demandes d'arrêt en supprimant les fichiers temporaires. Mais il vaut mieux que SIGQUIT ne les supprime pas, afin que l'utilisateur puisse les examiner conjointement avec le vidage de mémoire.

Et SIGHUP est également assez bien expliqué. SIGHUP n'est pas vraiment un signal de terminaison, cela signifie simplement que la "connexion" à l'utilisateur a été perdue, donc l'application ne peut pas s'attendre à ce que l'utilisateur lise une autre sortie (par exemple, la sortie stdout / stderr) et il n'y a aucune entrée à attendre du utilisateur plus. Pour la plupart des applications, cela signifie qu'il vaut mieux arrêter. En théorie, une application peut également décider qu'elle passe en mode démon lorsqu'un SIGHUP est reçu et s'exécute maintenant en tant que processus d'arrière-plan, en écrivant la sortie dans un fichier journal configuré. Pour la plupart des démons déjà exécutés en arrière-plan, SIGHUP signifie généralement qu'ils doivent réexaminer leurs fichiers de configuration, donc vous les envoyez aux processus d'arrière-plan après avoir édité les fichiers de configuration.

Cependant, il n'y a aucune explication utile de SIGINT sur cette page, à part qu'il est envoyé par CRTL + C. Y a-t-il une raison pour laquelle on traiterait SIGINT d'une manière différente de SIGTERM? Dans l'affirmative, quelle en serait la raison et en quoi le traitement serait-il différent?

Mecki
la source
1
Bonne question. Je soupçonne qu'une partie de la cruauté historique Unix serait impliquée dans la réponse.
Alex B
Je sais que cette question est ancienne, mais au cas où quelqu'un viendrait ici pour une liste complète de signaux pour votre système d'exploitation (Linux), ils peuvent être trouvés en tapant sudo fuser -lsur votre invite de commande. Pour moi, cela soulève: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
Essayez également kill -lune liste de signaux.
AAAfarmclub

Réponses:

88

SIGTERM et SIGKILL sont destinés aux demandes générales de «terminer ce processus». SIGTERM (par défaut) et SIGKILL (toujours) entraîneront l'arrêt du processus. SIGTERM peut être intercepté par le processus (par exemple pour qu'il puisse faire son propre nettoyage s'il le souhaite), ou même complètement ignoré; mais SIGKILL ne peut pas être attrapé ou ignoré.

SIGINT et SIGQUIT sont spécifiquement destinés aux demandes du terminal: des caractères d'entrée particuliers peuvent être affectés pour générer ces signaux (en fonction des paramètres de contrôle du terminal). L'action par défaut pour SIGINT est le même type d'arrêt de processus que l'action par défaut pour SIGTERM et l'action immuable pour SIGKILL; L'action par défaut pour SIGQUIT est également l'arrêt du processus, mais des actions supplémentaires définies par l'implémentation peuvent se produire, telles que la génération d'un vidage mémoire. L'un ou l'autre peut être intercepté ou ignoré par le processus si nécessaire.

SIGHUP, comme vous le dites, est destiné à indiquer que la connexion du terminal a été perdue, plutôt qu'à être un signal de terminaison en tant que tel. Mais, encore une fois, l'action par défaut pour SIGHUP (si le processus ne l'attrape pas ou ne l'ignore pas) est de terminer le processus de la même manière que SIGTERM etc.

Il existe un tableau dans les définitions POSIX pour signal.hlequel répertorie les différents signaux et leurs actions et objectifs par défaut, et le chapitre Interface générale du terminal comprend beaucoup plus de détails sur les signaux liés au terminal.

Matthew Slattery
la source
10
C'est le point clé: SIGINT et SIGQUIT peuvent être générés à partir du terminal en utilisant des caractères uniques, pendant que le programme est en cours d'exécution. Les autres signaux doivent être générés par un autre programme, d'une manière ou d'une autre (par exemple par la commande kill). SIGINT est moins violent que SIGQUIT; ce dernier produit un core dump. SIGKILL ne peut pas être piégé. SIGHUP est généré si votre connexion se bloque (la fenêtre se ferme, etc.). Donc, ils ont tous des significations différentes.
Jonathan Leffler
TTY Demystified a des informations faciles à digérer sur la manière dont les signaux interagissent avec le sous-système tty du noyau. Ajoute du contexte à votre réponse.
Daniel Näslund
2
On dirait que les spécifications ne sont pas très précises, mais je crois comprendre que SIgint demande au programme d'arrêter son action en cours, pas nécessairement de quitter. Pour un programme conçu, n'effectuez qu'une seule action par exécution qui implique de quitter, mais pour un programme interactif qui a une sorte de boucle lecture-évaluation-impression, cela peut signifier abandonner l'évaluation actuelle et revenir à la lecture de l'entrée utilisateur. Je pense que moins fait cela sur sigint.
bdsl
Quel signal est envoyé lors du redémarrage?
Dan Dascalescu
10

Comme DarkDust l'a noté, de nombreux signaux ont les mêmes résultats, mais les processus peuvent leur attacher différentes actions en distinguant la manière dont chaque signal est généré. En regardant le code source du noyau FreeBSD (kern_sig.c), je vois que les deux signaux sont traités de la même manière, ils terminent le processus et sont livrés à n'importe quel thread.

SA_KILL|SA_PROC,             /* SIGINT */
SA_KILL|SA_PROC,             /* SIGTERM */
Diomidis Spinellis
la source
9

man 7 signal

Ceci est la page de manuel non normative pratique du projet de pages de manuel Linux que vous souhaitez souvent consulter pour obtenir des informations sur les signaux Linux.

La version 3.22 mentionne des choses intéressantes telles que:

Les signaux SIGKILL et SIGSTOP ne peuvent pas être capturés, bloqués ou ignorés.

et contient le tableau:

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

qui résume le signal Actionqui distingue par exemple SIGQUIT de SIGQUIT, puisque SIGQUIT a une action Coreet SIGINT Term.

Les actions sont documentées dans le même document:

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.

Je ne vois aucune différence entre SIGTERM et SIGINT du point de vue du noyau car les deux ont une action Termet les deux peuvent être capturés. Il semble que ce ne soit qu'une "distinction de convention d'usage courant":

  • SIGINT est ce qui se passe lorsque vous faites CTRL-C à partir du terminal
  • SIGTERM est le signal par défaut envoyé par kill

Certains signaux sont ANSI C et d'autres non

Une différence considérable est que:

  • SIGINT et SIGTERM sont ANSI C, donc plus portables
  • SIGQUIT et SIGKILL ne sont pas

Ils sont décrits dans la section "7.14 Traitement des signaux" du projet C99 N1256 :

  • SIGINT réception d'un signal d'attention interactif
  • SIGTERM une demande de résiliation envoyée au programme

ce qui fait de SIGINT un bon candidat pour un Ctrl + C. interactif

POSIX 7

POSIX 7 documente les signaux avec l'en- signal.htête: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html

Cette page contient également le tableau d'intérêt suivant qui mentionne certaines des choses que nous avions déjà vues 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.

Init BusyBox

La rebootcommande par défaut 1.29.2 de BusyBox envoie un SIGTERM aux processus, se met en veille pendant une seconde, puis envoie SIGKILL. Cela semble être une convention commune dans différentes distributions.

Lorsque vous arrêtez un système BusyBox avec:

reboot

il envoie un signal au processus d'initialisation.

Ensuite, le gestionnaire de signal init finit par appeler:

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 */
}

qui imprime sur le terminal:

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

En voici un exemple concret minimal .

Signaux envoyés par le noyau

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

Après une recherche rapide sur Google pour sigint vs sigterm , il semble que la seule différence voulue entre les deux soit de savoir si elle a été initiée par un raccourci clavier ou par un appel explicite à kill.

En conséquence, vous pourriez, par exemple, intercepter sigint et faire quelque chose de spécial avec, sachant qu'il a probablement été envoyé par un raccourci clavier. Peut-être rafraîchir l'écran ou quelque chose, au lieu de mourir (non recommandé, car les gens s'attendent ^Cà tuer le programme, juste un exemple).

J'ai aussi appris que ^\devrait envoyer sigquit, que je pourrais commencer à utiliser moi-même. Ça a l'air très utile.

Jonathan
la source
3

En utilisant kill(à la fois l'appel système et l'utilitaire`, vous pouvez envoyer presque n'importe quel signal à n'importe quel processus, à condition que vous en ayez l'autorisation. Un processus ne peut pas distinguer comment un signal a pris vie et qui l'a envoyé.

Cela étant dit, SIGINT est vraiment destiné à chanter l'interruption Ctrl-C, tandis que SIGTERM est le signal général du terminal. Il n'y a pas de concept d'un signal «plus puissant», à la seule exception qu'il y a des signaux qui ne peuvent pas être bloqués ou traités (SIGKILL et SIGSTOP, selon la page de manuel).

Un signal ne peut être "plus puissant" qu'un autre signal en ce qui concerne la façon dont un processus de réception gère le signal (et quelle est l'action par défaut pour ce signal). Par exemple, par défaut, SIGTERM et SIGINT mènent à la terminaison. Mais si vous ignorez SIGTERM, cela ne mettra pas fin à votre processus, contrairement à SIGINT.

DarkDust
la source
0

À l'exception de quelques signaux, les gestionnaires de signaux peuvent capter les différents signaux, ou le comportement par défaut à la réception d'un signal peut être modifié. Consultez la signal(7)page de manuel pour plus de détails.

Ignacio Vazquez-Abrams
la source
Oui, mais si je ne connais pas "le sens" d'un singnal, capter le signal est inutile, car je ne saurai pas quoi faire dans mon application. GNU C explique par exemple la différence entre SIGQUIT et SIGTERM. Mais cela donne peu d'informations sur SIGINT: gnu.org/s/libc/manual/html_node/Termination-Signals.html
Mecki
"Le SIGINTsignal (" interruption de programme ") est envoyé lorsque l'utilisateur tape le caractère INTR (normalement C-c)." "SIGINT 2 Term Interrupt from keyboard" Vous appuyez sur Ctrl-C, SIGINTest envoyé. Le processus meurt normalement. Que donner de plus?
Ignacio Vazquez-Abrams
Potentiellement, il pourrait y avoir une description de l'intention que le programmeur devrait supposer que l'utilisateur aura lorsqu'il appuiera sur ctrl-c, c'est-à-dire la sémantique du message. À titre d'exemple, la spécification HTTP indique clairement que lorsqu'un utilisateur envoie une requête GET, le serveur ne doit pas supposer qu'il souhaite qu'il fasse autre chose que renvoyer une réponse.
bdsl