Dlaczego Ctrl-C nie działa?

9

Po prostu uderzyłem Ctrlcdwukrotnie moją skorupę, próbując zatrzymać proces, który zajmuje dużo czasu.

^C powtórzono dwukrotnie, ale proces po prostu trwał.

Dlaczego nie Ctrlczrezygnował z tego procesu tak jak zwykle?

lustro
źródło
4
Moim rozwiązaniem na irytujące programy, które nie chcą umrzeć, jest zwykle zawieszenie ich za pomocą CTRL + Z, a następnie kill -9 %ich zabicie. Sygnału 9 nie można zignorować, podobnie jak sygnał zawieszenia. Sekwencję klawiszy CTRL + Z można teoretycznie zignorować - ale nie ma tego w praktyce.
David Sainty,
@DavidSainty Sygnał zawieszenia można zignorować (lub przynajmniej nie zatrzymać). Przykład: perl -E '$SIG{TSTP} = sub { say "ha ha" }; sleep 1 while 1'. Prawdopodobnie myślisz o SIGSTOP, który jest innym sygnałem.
derobert
Ach, masz rację :)
David Sainty

Odpowiedzi:

13

Procesy mogą wybrać:

  • zignoruj ​​sygnał SIGINT zwykle wysyłany po naciśnięciu Ctrl-C(podobnie jak trap '' INTw powłoce) lub skorzystaj z własnego programu obsługi, który decyduje o nie kończeniu (lub nie kończy się w odpowiednim czasie).
  • powiedz urządzeniu końcowemu, że znak, który powoduje wysłanie SIGINT do zadania na pierwszym planie, jest czymś innym (jak stty int '^K'w przypadku powłoki)
  • powiedz urządzeniu końcowemu, aby nie wysyłało żadnego sygnału (jak stty -isigw przypadku powłoki).

Lub mogą być nieprzerwane, na przykład w trakcie wywołania systemowego, którego nie można przerwać.

W systemie Linux (ze stosunkowo nowym jądrem) możesz sprawdzić, czy proces ignoruje i / lub obsługuje SIGINT, patrząc na wynik działania

$ kill -l INT
2
$ grep Sig "/proc/$pid/status"
SigQ:   0/63858
SigPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000000000002
SigCgt: 0000000000000000

SIGINT to 2. Drugi bit SigIgn powyżej to 1, co oznacza, że ​​SIGINT jest ignorowany.

Możesz to zautomatyzować za pomocą:

$ SIG=$(kill -l INT) perl -lane 'print $1 if $F[0] =~ /^Sig(...):/ && 
    $F[1] & (1<<($ENV{SIG}-1))' < "/proc/$pid/status"
Ign

Aby sprawdzić, jaki jest obecny intrznak lub czy isigjest włączony dla danego terminala:

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

(powyżej intrznaku jest ^C(znak zwykle wysyłany przez terminal (emulator) po naciśnięciu, CTRL-Ca sygnały wejściowe nie są wyłączone.

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

( intrpostać jest ^Ki isigjest wyłączona dla /dev/pts/1).

Dla kompletności istnieją dwa inne sposoby, w jakie proces może zrobić coś, aby przestać otrzymywać SIGINT, chociaż zwykle nie jest to coś, co można by zobaczyć.

Na Ctrl+Csygnał SIGINT jest wysyłany do wszystkich procesów, w tym grupy procesów planie terminalu . Zwykle jest to powłoka, która umieszcza procesy w grupach procesów (mapowanych do zadań powłoki ) i informuje urządzenie końcowe, które jest na pierwszym planie .

Teraz proces może:

  • Opuść grupę procesów. Jeśli przejdzie do innej grupy procesów (dowolnej grupy procesów oprócz tej, która jest na pierwszym planie ), nie będzie już otrzymywał SIGINT po Ctrl-C(ani innych sygnałów związanych z klawiaturą, takich jak SIGTSTP, SIGQUIT). Może jednak zostać zawieszony, jeśli spróbuje odczytać (ewentualnie również w zależności od ustawień urządzenia końcowego) z urządzenia końcowego (tak jak robią to procesy w tle).

    Jako przykład:

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

    nie można przerwać Ctrl-C. Powyżej perlspróbuje dołączyć do grupy procesów, której identyfikator jest taki sam jak nadrzędny identyfikator procesu. Zasadniczo nie ma gwarancji, że istnieje taka grupa procesów o tym identyfikatorze. Ale tutaj, w przypadku tego perlpolecenia uruchamianego samodzielnie po zachęcie interaktywnej powłoki, ppid będzie procesem powłoki, a powłoka zwykle będzie uruchomiona we własnej grupie procesów.

    Jeśli polecenie nie jest już liderem grupy procesów (liderem tej grupy procesów pierwszego planu), wówczas uruchomienie nowej grupy procesów miałoby ten sam efekt.

    Na przykład w zależności od powłoki

    $ 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

    miałby ten sam efekt. psi perlsą uruchamiane w grupie procesowej na pierwszym planie, ale na większości powłok, psbędzie liderem tej grupy (jak widać na pswyjściu powyżej gdzie pgid obu psi perljest PID ps), więc perlmożna uruchomić własną grupę procesów.

  • Lub może zmienić grupę procesów pierwszego planu. Zasadniczo powiedz urządzeniu tty, aby wysłało SIGINT do innej grupy procesówCtrl+C

    perl -MPOSIX -e 'tcsetpgrp (0, getppid) lub die $ !; spać 5 '

    Tam, perlpozostaje w tej samej grupie procesu lecz mówi się, że urządzenie końcowe grupy procesów planie jest tym, którego identyfikator jest taki sam jak ID procesu nadrzędnego (patrz uwaga powyżej około tego).

Stéphane Chazelas
źródło
1
Dobrym przykładem nieprzerwanego połączenia jest dostęp do urządzenia sprzętowego, które nie odpowiada. Na przykład, jeśli spróbujesz użyć hdparmlub smartctlna uszkodzonym dysku twardym, który nie odpowiada, zawiesi się na zawsze i nie możesz ich zabić za pomocą CTRL + C. Możesz stwierdzić, czy proces jest w nieprzerwanym śnie, patrząc na kolumnę statystyk ps auxlub na kolumnę S w top/ htop- Doznacza nieprzerwany sen. To niekoniecznie jest zła rzecz, może to po prostu oznaczać, że proces wykonuje dużo IO.
Martin von Wittich,