J'utilise Ubuntu 14.04 et je rencontre ce problème que je n'arrive pas à comprendre:
- Exécutez la
yes
commande (dans le shell par défaut: Bash ) - Tapez CtrlZpour arrêter
yes
- Courez
jobs
. Production:
[1]+ Stopped yes
- Courez
kill -9 %1
pour vous arrêteryes
. Production:
[1]+ Stopped yes
- Courez
jobs
. Production:
[1]+ Stopped yes
C'est sur Ubuntu 3.16.0-30-generic
fonctionnant dans une machine virtuelle parallèle.
Pourquoi ma kill -9
commande n'a-t-elle pas mis fin à la commande oui ? Je pensais que SIGKILL ne pouvait pas être attrapé ou ignoré? Et comment puis-je terminer la commande yes ?
shell
job-control
s1m0n
la source
la source
uname -a
) s'il vous plaîtLinux ubuntu 3.16.0-30-generic #40~14.04.1-Ubuntu SMP Thu Jan 15 17:43:14 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
. J'utilise Ubuntu dans Parallels Desktop.(signal)
pour que vous puissiez faire la différence.Réponses:
Les signaux sont bloqués pour les processus suspendus. Dans un terminal:
Dans un deuxième terminal:
Dans le premier terminal:
Cependant,
SIGKILL
ne peut pas être bloqué. Faire la même chose aveckillall -9 yes
depuis le deuxième terminal donne immédiatement ceci dans leyes
terminal:Par conséquent, si
kill -9 %1
ne met pas fin au processus immédiatement, alors soitbash
vous n'envoyez pas le signal avantfg
le processus, soit vous avez découvert un bogue dans le noyau.la source
SIGTSTP
(qui est la version bloquable deSIGSTOP
) au processus actif. Cela met le processus dans un état figé où le noyau ne le planifie pas. Cela inhibe également le traitement du signal (à l'exception duSIGCONT
signal qui débloque le processus) et empêche donc le processus d'être immédiatement tué.SIGTERM
est bloqué, maisSIGKILL
ne l'est pas. Quoi qu'il en soit, selon un commentaire d'OP, le problème semble être qu'iljobs
ne détecte pas que le processus est mort, pas le processus qui n'est pas tué parkill -9 %1
.SIGKILL
qu'il ne puisse pas être bloqué, il n'y a aucune garantie qu'il sera livré dans un délai significatif. Si un processus est suspendu en attente de blocage, les E / S, par exemple,SIGKILL
n'arriveront pas avant la fin du processus. Cela pourrait potentiellement ne jamais se produire si aucune E / S ne se produit.Pas de panique.
Il n'y a rien de génial. Il n'y a pas de bug du noyau ici. Il s'agit d'un comportement parfaitement normal du shell Bourne Again et d'un système d'exploitation multitâche.
La chose à retenir est qu'un processus se tue , même en réponse à
SIGKILL
. Ce qui se passe ici, c'est que le shell Bourne Again se déplace aux choses avant que le processus qu'il vient de dire de se tuer ne se tue.Considérez ce qui se passe à partir du point où vous avez
yes
été arrêtéSIGTSTP
et vous venez d'exécuter lakill
commande avec le shell Bourne Again:SIGKILL
auyes
processus.yes
processus doit s'exécuter et se tue immédiatement.La raison pour laquelle vous voyez une chose et que d'autres personnes en voient une autre est une simple course entre deux processus prêts à fonctionner, dont le gagnant est entièrement dû à des choses qui varient d'une machine à l'autre et dans le temps. La charge du système fait une différence, tout comme le fait que votre CPU est virtuel.
Dans le cas intéressant, le détail de l'étape 2 est le suivant:
kill
commande intégrée, il marque l'entrée dans sa table de tâches comme nécessitant un message de notification imprimé au prochain point disponible.kill
commande et, juste avant d'imprimer à nouveau l'invite, vérifie s'il doit imprimer des messages de notification concernant les travaux.yes
processus n'a pas encore eu la chance de se tuer, donc en ce qui concerne le shell, le travail est toujours à l'état arrêté. Ainsi, le shell imprime une ligne d'état de travail "Arrêté" pour ce travail et réinitialise son indicateur de notification en attente.yes
processus est planifié et se tue.Les points importants sont:
SIGKILL
n'est pas magique. Les processus vérifient les signaux en attente lors du retour en mode application du mode noyau, ce qui se produit à la fin des erreurs de page, des interruptions (non imbriquées) et des appels système. La seule chose spéciale est que le noyau ne permet pas que l'action en réponseSIGKILL
soit autre chose qu'un suicide immédiat et inconditionnel, sans retour en mode application. Il est important de noter que les processus doivent à la fois effectuer des transitions du noyau au mode d'application et être planifiés pour s'exécuter afin de répondre aux signaux.set -o notify
). Ils sont imprimés lorsque le prochain shell atteint un point de son cycle d'exécution qu'il vérifie pour voir si des notifications sont en attente.kill
fois par leSIGCHLD
gestionnaire de signaux. Cela signifie que l'on peut voir deux messages si le shell est en cours d'exécution avant que leyes
processus soit reprogrammé pour se tuer; un message "Arrêté" et un message "Tué"./bin/kill
programme n'a aucun accès à la table des tâches internes du shell; vous ne verrez donc pas un tel comportement avec/bin/kill
. L'indicateur de notification en attente n'est défini qu'une seule fois, par leSIGCHLD
gestionnaire.kill
leyes
processus d' une autre coquille.la source
jobs
et le shell voit toujours le processus comme vivant. Ce serait une condition de concurrence de programmation inhabituellement longue. :)jobs
commandes de multiplication aprèskill
lesquelles toutes indiquent toujours que le processus est juste arrêté. Vous m'avez cependant inspiré à continuer d'expérimenter et je l'ai découvert: le message[1]+ Terminated yes
est imprimé dès que j'exécute une autre commande externe (pas un shell intégré commeecho
oujobs
). Je peux donc courirjobs
autant que je veux et ça continue d'imprimer[1]+ Stopped yes
. Mais dès que je coursls
par exemple, Bash imprime[1]+ Terminated yes
jobs
ne remarque pas que le processus est réellement mort ... Je ne sais pas quoi faire au sujet du statut mis à jour en exécutant une autre commande.Quelque chose de funky peut se produire sur votre système, sur le mien, votre recette fonctionne bien avec et sans le
-9
:Obtenez le pid avec
jobs -p
et essayez de le tuer commeroot
.la source
kill
commande interne de votre bash va plus loin et vérifie si le travail est gelé (vous voudrez peut-être essayer de trouver le PID du travail et de le tuer en utilisantenv kill <pid>
. De cette façon, vous utiliserez lakill
commande réelle et non la commande bash intégrée).which kill /usr/bin/kill
which
n'est pas un bash-builtin, doncwhich <anything>
vous donnera toujours le chemin vers la commande réelle. Mais essayez de comparer parkill --help
rapport/usr/bin/kill --help
.kill
.Ce que vous observez est un bug dans cette version de bash.
kill -9 %1
ne tue pas le travail immédiatement. Vous pouvez observer cela avecps
. Vous pouvez tracer le processus bash pour voir quand l'kill
appel système est appelé et tracer le sous-processus pour voir quand il reçoit et traite les signaux. Plus intéressant, vous pouvez aller voir ce qui se passe dans le processus.Dans un autre terminal:
Le sous-processus est un zombie . Il est mort: il ne lui reste qu'une entrée dans la table des processus (mais pas de mémoire, de code, de fichiers ouverts, etc.). L'entrée est conservée jusqu'à ce que son parent en prenne note et récupère son état de sortie en appelant l'
wait
appel système ou l'un de ses frères et sœurs .Un shell interactif est censé rechercher les enfants morts et les récolter avant d'imprimer une invite (sauf configuration contraire). Cette version de bash ne parvient pas à le faire dans certaines circonstances:
Vous pouvez vous attendre à ce que bash signale «Tué» dès qu'il imprime l'invite après la
kill
commande, mais ce n'est pas garanti, car il y a une condition de concurrence. Les signaux sont délivrés de manière asynchrone: l'kill
appel système revient dès que le noyau a déterminé le ou les processus auxquels délivrer le signal, sans attendre qu'il soit réellement délivré. Il est possible, et cela arrive dans la pratique, que bash ait le temps de vérifier l'état de son sous-processus, de constater qu'il n'est toujours pas mort (wait4
ne signale aucun décès d'enfant) et d'imprimer que le processus est toujours arrêté. Ce qui ne va pas, c'est qu'avant l'invite suivante, le signal a été délivré (ps
signale que le processus est mort), mais bash n'a toujours pas appeléwait4
(nous pouvons voir cela non seulement parce qu'il signale toujours le travail comme «Arrêté», mais parce que le zombie est toujours présent dans la table de processus). En fait, bash ne récolte le zombie que la prochaine fois qu'il doit appelerwait4
, lorsqu'il exécute une autre commande externe.Le bug est intermittent et je n'ai pas pu le reproduire pendant que bash est tracé (probablement parce que c'est une condition de concurrence où bash doit réagir rapidement). Si le signal est délivré avant les vérifications bash, tout se passe comme prévu.
la source