Warum hat Strg-C nicht funktioniert?

9

Ich habe nur Ctrlczweimal auf meine Muschel geschlagen, um einen Prozess anzuhalten, dessen Abschluss lange dauert.

^C wurde zweimal wiederholt, aber der Prozess ging einfach weiter.

Warum wurde Ctrlcder Prozess nicht wie gewohnt beendet?

der Spiegel
quelle
4
Meine Lösung für nervige Programme, die nicht sterben wollen, besteht normalerweise darin, sie mit STRG + Z anzuhalten und dann kill -9 %zu beenden. Signal 9 kann nicht ignoriert werden, ebenso wenig wie das Suspend-Signal. Die Tastenfolge STRG + Z kann theoretisch ignoriert werden - in der Praxis jedoch nicht.
David Sainty
@DavidSainty Das Suspend-Signal kann ignoriert werden (oder zumindest nicht gestoppt werden). Beispiel : perl -E '$SIG{TSTP} = sub { say "ha ha" }; sleep 1 while 1'. Sie denken wahrscheinlich an SIGSTOP, was ein anderes Signal ist.
Derobert
Ah, richtig du bist :)
David Sainty

Antworten:

13

Prozesse können wählen:

  • Ignorieren Sie das SIGINT-Signal, das normalerweise beim Drücken gesendet wird Ctrl-C(wie trap '' INTin einer Shell), oder verfügen Sie über einen eigenen Handler, der entscheidet, nicht zu beenden (oder nicht rechtzeitig zu beenden).
  • Teilen Sie dem Endgerät mit, dass das Zeichen, das bewirkt, dass ein SIGINT an den Vordergrundjob gesendet wird, etwas anderes ist (wie stty int '^K'in einer Shell).
  • Weisen Sie das Endgerät an, kein Signal zu senden (wie bei stty -isigeiner Shell).

Oder sie können unterbrechungsfrei sein, beispielsweise während eines Systemaufrufs, der nicht unterbrochen werden kann.

Unter Linux (mit einem relativ neuen Kernel) können Sie anhand der Ausgabe von feststellen, ob ein Prozess SIGINT ignoriert und / oder verarbeitet

$ 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 überprüfen Sie, was das aktuelle intrZeichen ist oder ob isiges für ein bestimmtes Terminal aktiviert ist:

$ stty -a < /dev/pts/0
[...] intr = ^C [...] isig

(über dem intrZeichen steht ^C(das Zeichen, das normalerweise von Ihrem Terminal (Emulator) gesendet wird, wenn das Drücken CTRL-Cund die Eingangssignale nicht deaktiviert sind.

$ stty -a < /dev/pts/1
[...] intr = ^K [...] -isig

( intrZeichen ist ^Kund isigist deaktiviert für /dev/pts/1).

Der Vollständigkeit halber gibt es zwei weitere Möglichkeiten, wie ein Prozess etwas tun kann, um den Empfang von SIGINTs zu beenden, obwohl dies normalerweise nicht der Fall ist.

Anschließend Ctrl+Cwird das SIGINT-Signal an alle Prozesse in der Vordergrundprozessgruppe des Terminals gesendet . In der Regel platziert die Shell Prozesse in Prozessgruppen (die Shell- Jobs zugeordnet sind ) und teilt dem Endgerät mit, welches das Vordergrundgerät ist .

Jetzt könnte ein Prozess:

  • Verlassen Sie die Prozessgruppe. Wenn es zu einer anderen Prozessgruppe wechselt (zu einer anderen Prozessgruppe als der Vordergrundgruppe ), wird das SIGINT nicht mehr empfangen Ctrl-C(und auch nicht die anderen tastaturbezogenen Signale wie SIGTSTP, SIGQUIT). Es kann jedoch angehalten werden, wenn versucht wird, vom Endgerät zu lesen (möglicherweise auch zu schreiben, abhängig von den Einstellungen des Endgeräts) (wie dies bei Hintergrundprozessen der Fall ist).

    Als Beispiel:

    perl -MPOSIX -e 'setpgid(0,getppid) or die "$!"; sleep 10'

    konnte nicht unterbrechbar sein mit Ctrl-C. Oben perlwird versucht, der Prozessgruppe beizutreten, deren ID mit der übergeordneten Prozess-ID übereinstimmt. Im Allgemeinen gibt es keine Garantie dafür, dass es eine solche Prozessgruppe mit dieser ID gibt. Im Fall dieses perlBefehls, der an der Eingabeaufforderung einer interaktiven Shell alleine ausgeführt wird, ist die ppid der Prozess der Shell, und die Shell wurde normalerweise in einer eigenen Prozessgruppe gestartet.

    Wenn der Befehl noch kein Prozessgruppenleiter ist (der Anführer dieser Vordergrundprozessgruppe), hat das Starten einer neuen Prozessgruppe den gleichen Effekt.

    Zum Beispiel, abhängig von der Shell,

    $ 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 den gleichen Effekt. psund perlwerden in der Vordergrund-Prozessgruppe gestartet, aber in den meisten Shells pswäre der Anführer dieser Gruppe (wie in der psobigen Ausgabe zu sehen, wo die pgid von beiden psund perldie pid von ps), perlkann also eine eigene Prozessgruppe starten.

  • Oder es könnte die Vordergrundprozessgruppe ändern. Weisen Sie das tty-Gerät grundsätzlich an, das SIGINT an eine andere Prozessgruppe zu sendenCtrl+C

    perl -MPOSIX -e 'tcsetpgrp (0, getppid) oder die $!; Schlaf 5 '

    Dort perlbleibt in der gleichen Prozeßgruppe , sondern wird das Endgerät mitteilt , dass der Vordergrundprozess Gruppe ist derjenige , der ID das gleiche ist wie seine Eltern - Prozess - ID (siehe Anmerkung oben darüber).

Stéphane Chazelas
quelle
1
Ein gutes Beispiel für einen unterbrechungsfreien Anruf ist der Zugriff auf ein Hardwaregerät, das nicht reagiert. Zum Beispiel, wenn Sie versuchen , zu verwenden , hdparmoder smartctlauf einer defekten Festplatte , die nicht reagiert sie für immer hängen, und Sie können sie mit STRG + C nicht töten. Sie können feststellen, ob sich ein Prozess im ununterbrochenen Schlaf befindet, indem Sie auf die stat-Spalte von ps auxoder auf die S-Spalte von top/ htop- schauen, Dwas ununterbrochenen Schlaf bedeutet. Dies ist jedoch nicht unbedingt eine schlechte Sache, es könnte nur bedeuten, dass der Prozess viel IO ausführt.
Martin von Wittich