web-dev-qa-db-fra.com

Comment SIGINT est-il lié aux autres signaux de terminaison tels que SIGTERM, SIGQUIT et SIGKILL?

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

  1. SIGTERM - demandez poliment à un processus de se terminer. Il doit se terminer normalement, nettoyer toutes les ressources (fichiers, sockets, processus enfants, etc.), supprimer les fichiers temporaires, etc.

  2. SIGQUIT - demande plus énergique. Cela mettra fin à un ingrat, 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 - demande la plus puissante. On ne demande même pas au processus de faire quoi que ce soit, mais le système nettoiera le processus, que cela plaise ou non. Un vidage de mémoire est très probablement écrit.

Comment SIGINT s'intègre-t-il dans cette image? Un processus CLI est généralement interrompu par SIGINT lorsque l'utilisateur frappe CRTL + C, mais un processus d'arrière-plan peut également être interrompu 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.

MISE À 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 y a une différence voulue entre SIGTERM et SIGQUIT.

Il 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 mémoire à la fin du 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 manipulation 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 d'autres sorties (par exemple, sortie stdout/stderr) et il n'y a aucune entrée à attendre de la utilisateur plus longtemps. Pour la plupart des applications, cela signifie qu'elles feraient mieux de cesser de fumer. En théorie, une application pourrait é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 fonctionnant déjà en arrière-plan, SIGHUP signifie généralement qu'ils doivent réexaminer leurs fichiers de configuration, vous les envoyez donc aux processus en arrière-plan après avoir modifié les fichiers de configuration.

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

91
Mecki

SIGTERM et SIGKILL sont destinés à des demandes générales de "fin de 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 être complètement ignoré; mais SIGKILL ne peut pas être capturé ou ignoré.

SIGINT et SIGQUIT sont spécifiquement destinés aux demandes du terminal: des caractères d'entrée particuliers peuvent être attribué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 de fin 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 de mémoire. L'un ou l'autre peut être pris 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 que d'ê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 l'ignore) est de terminer le processus de la même manière que SIGTERM etc.

Il y a un tableau dans les définitions POSIX pour signal.h qui répertorie les divers signaux et leurs actions et objectifs par défaut, et le chapitre General Terminal Interface contient beaucoup plus de détails sur les signaux liés au terminal.

74
Matthew Slattery

Comme DarkDust l'a noté, de nombreux signaux ont les mêmes résultats, mais les processus peuvent leur associer différentes actions en distinguant la façon 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 */
9
Diomidis Spinellis

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

Par conséquent, vous pouvez, par exemple, intercepter le 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 attendent ^C pour tuer le programme, juste un exemple).

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

7
Jonathan

man 7 signal

Il s'agit de la page de manuel pratique non normative 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 Action qui distingue par ex. SIGQUIT de SIGQUIT, car SIGQUIT a l'action Core et 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 l'action Term et les deux peuvent être interceptés. Il semble que ce soit juste une "distinction de convention d'utilisation courante":

  • SIGINT est ce qui se passe lorsque vous effectuez 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 C99 draft N1256 :

  • Réception SIGINT 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 le signal.h en-tê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 dans 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 commande reboot par défaut de BusyBox 1.29.2 envoie un SIGTERM aux processus, dort pendant une seconde, puis envoie SIGKILL. Cela semble être une convention commune à travers différentes distributions.

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

reboot

il envoie un signal au processus init.

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

Voici un exemple concret minimal de cela .

Signaux envoyés par le noyau

En utilisant kill (à la fois l'appel système et l'utilitaire), vous pouvez envoyer presque n'importe quel signal à n'importe quel processus, étant donné que vous en avez 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 terminal général. Il n'y a aucun concept d'un signal "plus puissant", à la seule exception qu'il existe des signaux qui ne peuvent pas être bloqués ou manipulés (SIGKILL et SIGSTOP, selon la page de manuel).

Un signal ne peut être "plus énergique" 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 conduisent à la résiliation. Mais si vous ignorez SIGTERM, cela ne mettra pas fin à votre processus, alors que SIGINT le fait toujours.

3
DarkDust

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

0