Dans quel ordre dois-je envoyer des signaux aux processus d'arrêt normal?

88

Dans un commentaire sur cette réponse à une autre question , le commentateur dit:

n'utilisez pas kill -9 sauf si c'est absolument nécessaire! SIGKILL ne peut pas être piégé, donc le programme tué ne peut exécuter aucune routine d'arrêt pour par exemple effacer les fichiers temporaires. Essayez d'abord HUP (1), puis INT (2), puis QUIT (3)

Je suis d'accord sur le principe SIGKILL, mais le reste est une nouvelle pour moi. Étant donné que le signal par défaut envoyé par killest SIGTERM, je m'attendrais à ce que ce soit le signal le plus couramment attendu pour l'arrêt progressif d'un processus arbitraire. En outre, j'ai vu SIGHUPutilisé pour des raisons non terminales, telles que dire à un démon "relisez votre fichier de configuration". Et il me semble que SIGINT(la même interruption que vous obtenez généralement avec Ctrl-C, n'est-ce pas?) N'est pas aussi largement supportée qu'elle devrait l'être, ou se termine plutôt sans grâce.

Étant donné qu'il SIGKILLs'agit d'un dernier recours - Quels signaux, et dans quel ordre , devez-vous envoyer à un processus arbitraire, afin de l'arrêter le plus gracieusement possible?

Veuillez étayer vos réponses avec des faits à l'appui (au-delà de vos préférences ou opinions personnelles) ou des références, si vous le pouvez.

Remarque: je suis particulièrement intéressé par les meilleures pratiques qui incluent la prise en compte de bash / Cygwin.

Edit: Jusqu'à présent, personne ne semble mentionner INT ou QUIT, et il y a une mention limitée de HUP. Y a-t-il une raison de les inclure dans un processus de mise à mort ordonné?

PAUSE système
la source
4
Si vous devez recourir à SIGKILL pour vraiment tuer un processus, je considérerais cela comme un bogue dans le programme.
sigjuice

Réponses:

114

SIGTERM demande à une application de se terminer. Les autres signaux indiquent à l'application d'autres choses qui ne sont pas liées à l'arrêt mais qui peuvent parfois avoir le même résultat. Ne les utilisez pas. Si vous souhaitez qu'une application s'arrête, dites-lui de le faire. Ne lui donnez pas de signaux trompeurs.

Certaines personnes pensent que la manière standard intelligente de terminer un processus consiste à lui envoyer une multitude de signaux, tels que HUP, INT, TERM et enfin KILL. C'est ridicule. Le bon signal pour la terminaison est SIGTERM et si SIGTERM ne termine pas le processus instantanément, comme vous pourriez le préférer, c'est parce que l'application a choisi de gérer le signal. Ce qui signifie qu'il a une très bonne raison de ne pas s'arrêter immédiatement: il y a un travail de nettoyage à faire. Si vous interrompez ce travail de nettoyage avec d'autres signaux, il est impossible de dire quelles données de la mémoire elles n'ont pas encore sauvegardées sur le disque, quelles applications clientes sont laissées en suspens ou si vous l'interrompez "au milieu de la phrase", ce qui est en fait une corruption de données.

Pour plus d'informations sur la signification réelle des signaux, voir sigaction (2). Ne confondez pas "Action par défaut" avec "Description", ce n'est pas la même chose.

SIGINT est utilisé pour signaler une "interruption clavier" interactive du processus. Certains programmes peuvent gérer la situation d'une manière spéciale pour les utilisateurs de terminaux.

SIGHUP est utilisé pour signaler que le terminal a disparu et ne regarde plus le processus. C'est tout. Certains processus choisissent de s'arrêter en réponse, généralement parce que leur fonctionnement n'a aucun sens sans un terminal, certains choisissent de faire d'autres choses telles que revérifier les fichiers de configuration.

SIGKILL est utilisé pour supprimer de force le processus du noyau. Il est spécial en ce sens qu'il ne s'agit pas en fait d'un signal adressé au processus mais qu'il est plutôt directement interprété par le noyau.

N'envoyez pas SIGKILL. SIGKILL ne devrait certainement jamais être envoyé par des scripts. Si l'application gère le SIGTERM, le nettoyage peut prendre une seconde, cela peut prendre une minute, cela peut prendre une heure . En fonction de ce que l'application doit faire avant qu'elle ne soit prête à se terminer. Toute logique qui " suppose " la séquence de nettoyage d'une application a pris suffisamment de temps et doit être raccourcie ou SIGKILLed après X secondes est tout simplement fausse .

La seule raison pour laquelle une application aurait besoin d' un SIGKILL pour se terminer, est si quelque chose a été bugué pendant sa séquence de nettoyage. Dans ce cas, vous pouvez ouvrir un terminal et le SIGKILL manuellement. En dehors de cela, la seule autre raison pour laquelle vous SIGKILLZ quelque chose est parce que vous VOULEZ l' empêcher de se nettoyer.

Même si la moitié du monde envoie aveuglément SIGKILL après 5 secondes, c'est toujours une chose horriblement mal à faire.

lhunath
la source
13
Vous avez raison de dire qu'il y a beaucoup d'abus de SIGKILL là-bas. Mais il y a un moment et un lieu pour l'utiliser, même à partir d'un script. De nombreuses applications piègent SIGTERM et se terminent gracieusement en moins d'une seconde ou en quelques secondes, et l'une d'entre elles fonctionne toujours 30 secondes plus tard, car elle est coincée.
dwc
4
@dwc: essayez de le laisser fonctionner une fois pendant une heure. S'il ne meurt pas, il est "coincé" et corrige-le, ou soit paresseux et à l'avenir SIGKILL après un certain temps. Prenez note que vous êtes probablement en train de corrompre des choses et rappelez-vous que ce n'est PAS quelque chose que vous devriez faire "par défaut".
lhunath
2
@lhunath: J'espère que cela ne vous dérange pas, j'ai réorganisé vos paragraphes afin que la réponse découle plus directement et clairement de la question. La diatribe anti-SIGKILL est une bonne chose, mais un point secondaire. Merci encore pour une excellente réponse éducative.
système PAUSE
8
N'envoyez pas SIGKILL. Déjà. Tout simplement faux. Vraiment? Même si votre système brûle déjà grâce à des boucles infinies. Bonne chance. -1
konsolebox
//, voter pour Ceci est ridicule.
Nathan Basanese
17

Réponse courte : Envoyer SIGTERM, 30 secondes plus tard, SIGKILL. Autrement dit, envoyez SIGTERM, attendez un peu (cela peut varier d'un programme à l'autre, vous connaissez peut-être mieux votre système, mais 5 à 30 secondes suffisent. Lors de l'arrêt d'une machine, vous pouvez la voir attendre automatiquement jusqu'à 1'30s. Pourquoi la hâte, après tout?), Puis envoyez SIGKILL.

Raisonnable Réponse : SIGTERM, SIGINT, SIGKILL C'est plus que suffisant. Le processus se terminera très probablement avant SIGKILL.

Réponse longue : SIGTERM, SIGINT, SIGQUIT, SIGABRT,SIGKILL

Cela n'est pas nécessaire, mais au moins vous n'induisez pas en erreur le processus concernant votre message. Tous ces signaux ne signifient que vous voulez que le processus pour arrêter ce qu'il fait et la sortie.

Quelle que soit la réponse que vous choisissez dans cette explication, gardez cela à l'esprit!

Si vous envoyez un signal qui signifie autre chose, le processus peut le gérer de manière très différente (d'une part). D'un autre côté, si le processus ne gère pas le signal, peu importe ce que vous envoyez après tout, le processus s'arrêtera de toute façon (lorsque l'action par défaut est de se terminer, bien sûr).

Donc, vous devez penser comme vous-même en tant que programmeur. Coderiez-vous un gestionnaire de fonctions pour, disons, SIGHUPquitter un programme qui se connecte à quelque chose, ou le feriez-vous en boucle pour essayer de vous connecter à nouveau? Telle est la question principale ici! C'est pourquoi il est important d'envoyer simplement des signaux qui signifient ce que vous souhaitez.

Réponse longue presque stupide :

Le tableau ci-dessous contient les signaux pertinents et les actions par défaut au cas où le programme ne les gère pas.

Je les ai commandés dans l'ordre que je suggère d'utiliser (BTW, je vous suggère d'utiliser la réponse raisonnable , pas celle-ci ici), si vous avez vraiment besoin de tous les essayer (ce serait amusant de dire que la table est ordonnée en termes de la destruction qu'ils peuvent causer, mais ce n'est pas tout à fait vrai).

Les signaux avec un astérisque (*) ne sont PAS recommandés. La chose importante à ce sujet est que vous ne saurez peut-être jamais ce pour quoi il est programmé. Surtout SIGUSR! Cela peut démarrer l'apocalipse (c'est un signal gratuit pour un programmeur qui fait ce qu'il veut!). Mais, s'il n'est pas traité OU dans le cas peu probable où il est traité pour se terminer, le programme se terminera.

Dans le tableau, les signaux avec les options par défaut pour terminer et générer un vidage de mémoire sont laissés à la fin, juste avant SIGKILL.

Signal     Value     Action   Comment
----------------------------------------------------------------------
SIGTERM      15       Term    Termination signal
SIGINT        2       Term    Famous CONTROL+C interrupt from keyboard
SIGHUP        1       Term    Disconnected terminal or parent died
SIGPIPE      13       Term    Broken pipe
SIGALRM(*)   14       Term    Timer signal from alarm
SIGUSR2(*)   12       Term    User-defined signal 2
SIGUSR1(*)   10       Term    User-defined signal 1
SIGQUIT       3       Core    CONTRL+\ or quit from keyboard
SIGABRT       6       Core    Abort signal from abort(3)
SIGSEGV      11       Core    Invalid memory reference
SIGILL        4       Core    Illegal Instruction
SIGFPE        8       Core    Floating point exception
SIGKILL       9       Term    Kill signal

Ensuite , je suggère pour cette longue réponse presque stupide : SIGTERM, SIGINT, SIGHUP, SIGPIPE, SIGQUIT, SIGABRT,SIGKILL

Et enfin, le

Réponse longue et longue définitivement stupide :

N'essayez pas ca a la maison.

SIGTERM, SIGINT, SIGHUP, SIGPIPE, SIGALRM, SIGUSR2, SIGUSR1, SIGQUIT, SIGABRT, SIGSEGV, SIGILL, SIGFPEEt si rien ne fonctionnait, SIGKILL.

SIGUSR2devrait être essayé avant SIGUSR1car nous sommes mieux si le programme ne gère pas le signal. Et il est beaucoup plus probable qu'il gère SIGUSR1s'il ne gère qu'un seul d'entre eux.

BTW, the KILL : il n'est pas faux d'envoyer SIGKILLà un processus, comme une autre réponse l'a indiqué. Eh bien, pensez à ce qui se passe lorsque vous envoyez une shutdowncommande? Il essaiera SIGTERMet SIGKILLseulement. Pourquoi pensez-vous que c'est le cas? Et pourquoi avez-vous besoin d'autres signaux, si la shutdowncommande même n'utilise que ces deux?


Maintenant, revenons à la longue réponse , c'est un joli oneliner:

for SIG in 15 2 3 6 9 ; do echo $SIG ; echo kill -$SIG $PID || break ; sleep 30 ; done

Il dort pendant 30 secondes entre les signaux. Sinon, pourquoi auriez-vous besoin d'un oneliner ? ;)

Aussi, recommandé: essayez-le avec uniquement les signaux 15 2 9de la réponse raisonnable .

sécurité : retirez le second echolorsque vous êtes prêt à partir. Je l'appelle mon dry-runpour les onliners . Utilisez-le toujours pour tester.


Script tuer avec grâce

En fait, j'étais tellement intrigué par cette question que j'ai décidé de créer un petit script pour faire exactement cela. N'hésitez pas à le télécharger (cloner) ici:

Lien GitHub vers le référentiel Killgracefully

DrBeco
la source
8

En règle générale, vous enverriez SIGTERM, la valeur par défaut de kill. C'est la valeur par défaut pour une raison. Ce n'est que si un programme ne s'arrête pas dans un délai raisonnable que vous devez recourir à SIGKILL. Mais notez qu'avec SIGKILLle programme n'a aucune possibilité de nettoyer les choses et les données pourraient être corrompues.

Quant à SIGHUP, HUPsignifie "raccrocher" et signifie historiquement que le modem s'est déconnecté. C'est essentiellement équivalent à SIGTERM. La raison pour laquelle les démons utilisent parfois SIGHUPpour redémarrer ou recharger la configuration est que les démons se détachent de tout terminal de contrôle car un démon n'en a pas besoin et ne les reçoit donc jamais SIGHUP, de sorte que le signal a été considéré comme "libéré" pour une utilisation générale. Tous les démons ne l'utilisent pas pour recharger! L'action par défaut pour SIGHUP est de se terminer et de nombreux démons se comportent de cette façon! Vous ne pouvez donc pas envoyer aveuglément des SIGHUPs aux démons et vous attendre à ce qu'ils survivent.

Edit: SIGINT est probablement inapproprié pour terminer un processus, car il est normalement lié ^Cou quel que soit le paramètre du terminal pour interrompre un programme. De nombreux programmes capturent cela à leurs propres fins, il est donc assez courant pour que cela ne fonctionne pas. SIGQUITa généralement la valeur par défaut de créer un vidage de mémoire, et à moins que vous ne vouliez que les fichiers de base soient installés, ce n'est pas non plus un bon candidat.

Résumé: si vous envoyez SIGTERMet que le programme ne meurt pas dans votre délai, envoyez-le SIGKILL.

dwc
la source
4
Notez que le suivi avec SIGKILL ne doit être effectué que dans les situations où l'arrêt instantané est une priorité plus élevée que la prévention de la perte de données / de la corruption des données.
thomasrutter
@dwc Je n'ai pas compris le point suivant de votre réponse. pourriez-vous s'il vous plaît aider "La raison pour laquelle les démons utilisent parfois SIGHUP pour redémarrer ou recharger la configuration est que les démons se détachent de tout terminal de contrôle et ne recevraient donc jamais SIGTERM, de sorte que le signal était considéré comme" libéré "pour une utilisation générale."
Jack
3
@Jack Laissez-moi essayer: SIGHUP est le signal "raccrocher" qui indique à un processus que le terminal s'est déconnecté. Puisque les démons fonctionnent en arrière-plan, ils n'ont pas besoin de terminaux. Cela signifie qu'un signal "raccrocher" n'est pas pertinent pour les démons. Ils ne le recevront jamais d'une déconnexion de terminal, car ils n'ont pas de terminaux connectés en premier lieu. Et comme le signal est défini de toute façon, bien qu'ils n'en aient pas besoin pour le but initial, de nombreux démons l'utilisent à la place dans un but différent, comme la relecture de leurs fichiers de configuration.
système PAUSE
Merci système PAUSE. c'est utile.
Jack
6

SIGTERMsignifie en fait envoyer à une application un message: « seriez-vous si gentil et vous suicideriez-vous ». Il peut être piégé et géré par l'application pour exécuter le code de nettoyage et d'arrêt.

SIGKILLne peut pas être piégé par l'application. L'application est tuée par le système d'exploitation sans aucune chance de nettoyage.

Il est courant d'envoyer d' SIGTERMabord, de dormir quelque temps, puis d'envoyer SIGKILL.

vartec
la source
Je suppose que le sondage serait un peu plus efficace que de dormir (avant le SIGKILL)
Ohad Schneider
@OhadSchneider ça le ferait, mais cela nécessiterait quelque chose de plus qu'une simple commande bash.
vartec le
Ouais, je suppose que vous auriez besoin de boucler pendant que le processus est toujours en cours en utilisant quelque chose comme ceci: stackoverflow.com/a/15774758/67824 .
Ohad Schneider
5
  • SIGTERM équivaut à "cliquer sur le 'X'" dans une fenêtre.
  • SIGTERM est ce que Linux utilise en premier, lorsqu'il s'arrête.
gbarry
la source
C'est ce que je voulais savoir. +1. Merci.
Luc
6
"SIGTERM équivaut à" cliquer sur le 'X' "dans une fenêtre" Non, ce n'est pas le cas, car une application peut facilement ouvrir n'importe quel nombre de fenêtres (document et outil, par exemple), sans parler des boîtes de dialogue, et il se peut que ce ne soit pas le cas. même répondre à une dernière commande de fermeture de fenêtre comme à une commande de sortie (je ne peux penser à aucun exemple évident, mais bien que non évident, il n'y a aucune raison pour que cela ne puisse pas être fait de cette façon). SIGTERM est (ou devrait être) équivalent à demander gracieusement à l'application de se terminer, mais cela peut être effectué dans cette application particulière .
utilisateur
3

Avec toute la discussion en cours ici, aucun code n'a été proposé. Voici ma prise:

#!/bin/bash

$pid = 1234

echo "Killing process $pid..."
kill $pid

waitAttempts=30 
for i in $(seq 1 $waitAttempts)
do
    echo "Checking if process is alive (attempt #$i / $waitAttempts)..."
    sleep 1

    if ps -p $pid > /dev/null
    then
        echo "Process $pid is still running"
    else
        echo "Process $pid has shut down successfully"
        break
    fi
done

if ps -p $pid > /dev/null
then
    echo "Could not shut down process $pid gracefully - killing it forcibly..."
    kill -SIGKILL $pid
fi
Ohad Schneider
la source
0

HUP me semble être des ordures. Je l'enverrais pour qu'un démon relise sa configuration.

SIGTERM peut être intercepté; vos démons peuvent simplement avoir un code de nettoyage à exécuter lorsqu'ils reçoivent ce signal. Vous ne pouvez pas faire cela pour SIGKILL. Ainsi, avec SIGKILL, vous ne donnez aucune option à l'auteur du démon.

Plus à ce sujet sur Wikipedia

innaM
la source