Чому Ctrl-C не працював?


9

Я просто Ctrlcдвічі вдарив об свою оболонку, намагаючись зупинити процес, який триває багато часу.

^C лунав двічі, але процес просто продовжувався.

Чому не Ctrlcвийшов з процесу, як це зазвичай?


4
Моє рішення для дратівливих програм, які не хочуть померти, - це зазвичай призупинити їх CTRL + Z, а потім kill -9 %вбити. Сигнал 9 не можна ігнорувати, а також сигнал призупинення не може. Послідовність клавіатур CTRL + Z теоретично можна ігнорувати - але це не на практиці.
Девід Сенті

@DavidSainty Призупинений сигнал можна ігнорувати (або, принаймні, не зупиняти). Приклад: perl -E '$SIG{TSTP} = sub { say "ha ha" }; sleep 1 while 1'. Ви, напевно, думаєте про SIGSTOP, який є іншим сигналом.
дероберт

Ах, правда ти :)
Девід Сенті,

Відповіді:


13

Процеси можуть вибрати:

  • ігнорувати сигнал SIGINT, який зазвичай надсилається після натискання Ctrl-C(як trap '' INTу оболонці), або мати власного обробника для нього, який вирішує не припиняти (або не вдається припинити своєчасно).
  • скажіть термінальному пристрою, що символ, який викликає надсилання SIGINT на завдання переднього плану, є чимось іншим (наприклад, stty int '^K'в оболонці)
  • скажіть термінальному пристрою не надсилати жодного сигналу (наприклад, stty -isigв оболонці).

Або вони можуть бути безперебійними, як, наприклад, в середині системного дзвінка, який неможливо перервати.

У Linux (із відносно недавнім ядром) ви можете дізнатися, чи процес ігнорує та / або обробляє SIGINT, переглянувши вихід

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

SIGINT - 2. Другий біт SigIgn вище - 1, що означає, що SIGINT ігнорується.

Ви можете автоматизувати це за допомогою:

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

Щоб перевірити, що є поточним intrсимволом або якщо isigвін увімкнено для даного терміналу:

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

(вище intrсимволу є ^C(символ, який зазвичай надсилається вашим терміналом (емулятором), коли натискання CTRL-Cта введення сигналів не вимкнено).

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

( intrсимвол є ^Kі isigвимкнено для /dev/pts/1).

Для повноти є два інші способи, які можуть зробити щось, щоб припинити отримання SIGINT, хоча це зазвичай не те, що ви бачите.

Після Ctrl+Cцього сигнал SIGINT надсилається всім процесам в передній план групи процесів терміналу . Зазвичай оболонка розміщує процеси в групах процесів (відображаються на завданнях оболонок ) і повідомляє кінцевому пристрою, який є на передньому плані .

Тепер процес міг:

  • Залиште його процесну групу. Якщо він переміститься до іншої групи процесів (будь-якої групи процесів, окрім тієї, що є передньою формою ), вона більше не буде отримувати ЗНАК Ctrl-C(ні інші сигнали, пов'язані з клавіатурою, такі як SIGTSTP, SIGQUIT). Однак він може бути призупинений, якщо він спробує прочитати (можливо, також добре, залежно від налаштувань термінального пристрою) з термінального пристрою (як це роблять фонові процеси).

    Як приклад:

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

    не вдалося перервати Ctrl-C. Вище perlнамагатиметься приєднатися до групи процесів, ідентифікатор якої збігається з ідентифікатором батьківського процесу. Загалом, немає гарантії, що існує така група процесів з цим ідентифікатором. Але тут, у випадку, коли ця perlкоманда запускається самостійно під час запиту інтерактивної оболонки, ppid буде процесом оболонки, і оболонка, як правило, запускається у власній групі процесів.

    Якщо команда вже не є лідером групи процесів (керівником цієї передньої групи процесу), то запуск нової групи процесів матиме такий же ефект.

    Наприклад, залежно від оболонки,

    $ 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

    матиме такий же ефект. psі perlзапускаються в групі процесу переднього плану, але на більшості оболонок psбуде лідером цієї групи (як видно з psрезультатів вище, де pgid обох psі perlє pid ps), тому perlможе запустити власну групу процесу.

  • Або це може змінити групу процесу переднього плану. В основному, скажіть пристрою tty, щоб надсилати SIGINT до якоїсь іншої групи процесівCtrl+C

    perl -MPOSIX -e 'tcsetpgrp (0, getppid) або die $ !; спати 5 '

    Там perlзалишається в тій самій групі процесів, але натомість повідомляє термінальному пристрою, що група процесу переднього плану - це та сама, ідентифікатор якої збігається з ідентифікатором батьківського процесу (див. Примітку вище про це).


1
Хорошим прикладом безперебійного дзвінка є доступ до апаратного пристрою, який не відповідає. Наприклад, якщо ви намагаєтесь використовувати hdparmабо smartctlна несправному жорсткому диску, який не відповідає, він зависне назавжди, і ви не зможете вбити їх за допомогою CTRL + C. Ви можете визначити, чи перебуває процес у режимі безперебійного сну, переглянувши стовпець stat ps auxабо колонку S top/ htop- Dозначає режим безперебійного сну. Це не обов'язково погано, але це може просто означати, що процес робить багато IO.
Мартін фон Віттіч
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.