Ich habe gerade Ctrlczweimal auf meine Shell geschlagen, um einen Vorgang anzuhalten, der sehr lange dauert.
^C
wurde zweimal wiederholt, aber der Vorgang ging einfach weiter.
Warum wurde Ctrlcder Vorgang nicht wie gewohnt beendet?
Antwort1
Prozesse können Folgendes wählen:
- Ignorieren Sie das SIGINT-Signal, das normalerweise beim Drücken gesendet wird Ctrl-C(wie
trap '' INT
in einer Shell), oder verfügen Sie über einen eigenen Handler dafür, der sich entscheidet, nicht zu beenden (oder nicht rechtzeitig zu beenden). - dem Endgerät mitteilen, dass das Zeichen, das die Übermittlung eines SIGINT an den Vordergrundjob bewirkt, ein anderes ist (wie in
stty int '^K'
einer Shell) - sagen Sie dem Endgerät, dass es kein Signal senden soll (wie
stty -isig
in einer Shell).
Oder sie können nicht unterbrechungsfähig sein, beispielsweise mitten in einem Systemaufruf, der nicht unterbrochen werden kann.
Unter Linux (mit einem relativ neuen Kernel) können Sie erkennen, ob ein ProzessHandhabungSIGINT durch Betrachten der Ausgabe von
$ kill -l INT
2
$ grep Sig "/proc/$pid/status"
SigQ: 0/63858
SigPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000000000002
SigCgt: 0000000000000000
SIGINT ist 2. Das zweite Bit von SigIgn oben ist 1, was bedeutet, dass SIGINT ignoriert wird.
Sie können dies automatisieren mit:
$ SIG=$(kill -l INT) perl -lane 'print $1 if $F[0] =~ /^Sig(...):/ &&
$F[1] & (1<<($ENV{SIG}-1))' < "/proc/$pid/status"
Ign
So prüfen Sie, welches das aktuelle intr
Zeichen ist oder ob isig
es für ein bestimmtes Terminal aktiviert ist:
$ stty -a < /dev/pts/0
[...] intr = ^C [...] isig
(über dem intr
Zeichen steht ^C
(das Zeichen, das normalerweise von Ihrem Terminal (Emulator) gesendet wird, wenn Sie drücken CTRL-Cund die Eingabesignale nicht deaktiviert sind.
$ stty -a < /dev/pts/1
[...] intr = ^K [...] -isig
( intr
Zeichen ist ^K
und isig
ist deaktiviert für /dev/pts/1
).
Der Vollständigkeit halber sei erwähnt, dass es noch zwei weitere Möglichkeiten gibt, wie ein Prozess den Empfang von SIGINTs beenden kann. Dies ist jedoch nichts, was man normalerweise sieht.
Daraufhin Ctrl+Cwird das Signal SIGINT an alle Prozesse imVordergrundprozessgruppe des Terminals. Normalerweise ist es die Shell, die Prozesse in Prozessgruppen einordnet (abgebildet auf ShellArbeitsplätze) und teilen Sie dem Endgerät mit, welchesVordergrundeins.
Nun könnte ein Prozess:
Verlassen Sie die Prozessgruppe. Wenn es in eine andere Prozessgruppe wechselt (jede andere als die, die dieVordergrundeins), dann empfängt es nicht mehr das SIGINT Ctrl-C(und auch keine anderen tastaturbezogenen Signale wie SIGTSTP, SIGQUIT). Es könnte jedoch angehalten werden, wenn es versucht, vom Terminalgerät zu lesen (und je nach den Einstellungen des Terminalgeräts möglicherweise auch zu schreiben) (wie es Hintergrundprozesse tun).
Als Beispiel:
perl -MPOSIX -e 'setpgid(0,getppid) or die "$!"; sleep 10'
konnte nicht unterbrochen werden mit Ctrl-C. Oben
perl
wird versucht, der Prozessgruppe beizutreten, deren ID mit der ID des übergeordneten Prozesses übereinstimmt. Im Allgemeinen gibt es keine Garantie dafür, dass es eine solche Prozessgruppe mit dieser ID gibt. Aber hier, im Fall diesesperl
Befehls, der allein an der Eingabeaufforderung einer interaktiven Shell ausgeführt wird, ist die ppid der Prozess der Shell und die Shell wurde normalerweise in ihrer eigenen Prozessgruppe gestartet.Wenn der Befehl nicht bereits ein Prozessgruppenleiter ist (der Leiter dieser Vordergrundprozessgruppe), hätte das Starten einer neuen Prozessgruppe dieselbe Wirkung.
Je nach Shell beispielsweise
$ ps -j >&2 | perl -MPOSIX -e 'setpgid(0,0) or die "$!"; sleep 10' PID PGID SID TTY TIME CMD 21435 21435 21435 pts/12 00:00:00 zsh 21441 21441 21435 pts/12 00:00:00 ps 21442 21441 21435 pts/12 00:00:00 perl
hätte dieselbe Wirkung.
ps
undperl
werden in der Vordergrundprozessgruppe gestartet,ps
wäre aber auf den meisten Shells der Anführer dieser Gruppe (wie in derps
Ausgabe oben zu sehen ist, wo die pgid sowohl vonps
als auchperl
die pid von istps
),perl
kann also seine eigene Prozessgruppe starten.Oder es könnte die Vordergrund-Prozessgruppe ändern. Sagen Sie dem TTY-Gerät im Grunde, dass es das SIGINT an eine andere Prozessgruppe senden soll, wennCtrl+C
perl -MPOSIX -e 'tcsetpgrp(0,getppid) or die$!; sleep 5'
Dort
perl
bleibt es in derselben Prozessgruppe, teilt dem Endgerät jedoch stattdessen mit, dass die Vordergrundprozessgruppe diejenige ist, deren ID mit der ID ihres übergeordneten Prozesses übereinstimmt (siehe Anmerkung oben).