Почему не сработало Ctrl-C?

Почему не сработало Ctrl-C?

Я только что Ctrlcдважды ударил по своей раковине, пытаясь остановить процесс, который затягивается надолго.

^Cповторилось дважды, но процесс продолжался.

Почему не Ctrlcпрекратили этот процесс, как это обычно происходит?

решение1

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

  • игнорировать сигнал 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 отправляется всем процессам вгруппа процессов переднего плана терминала. Обычно именно оболочка помещает процессы в группы процессов (отображаемые в оболочкерабочие места) и сообщите терминальному устройству, какое из них являетсяпередний планодин.

Теперь процесс может:

  • Покинуть свою группу процессов. Если он переходит в другую группу процессов (любую группу процессов, кроме той, которая являетсяпередний планone), то он больше не будет получать 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) or die$!; sleep 5'
    

    Там perlон остается в той же группе процессов, но вместо этого сообщает терминальному устройству, что группа процессов переднего плана — это та, идентификатор которой совпадает с идентификатором ее родительского процесса (см. примечание выше по этому поводу).

Связанный контент