
Acabei de bater Ctrlcduas vezes no meu shell na tentativa de interromper um processo que está demorando muito para terminar.
^C
foi repetido duas vezes, mas o processo continuou.
Por que não Ctrlcencerrou o processo como normalmente acontece?
Responder1
Os processos podem optar por:
- ignore o sinal SIGINT geralmente enviado ao pressionar Ctrl-C(como
trap '' INT
em um shell) ou tenha seu próprio manipulador que decida não encerrar (ou não finalize em tempo hábil). - diga ao dispositivo terminal que o caractere que faz com que um SIGINT seja enviado para o trabalho em primeiro plano é outra coisa (como
stty int '^K'
em um shell) - diga ao dispositivo terminal para não enviar nenhum sinal (como
stty -isig
em um shell).
Ou podem ser ininterruptos, como no meio de uma chamada do sistema que não pode ser interrompida.
No Linux (com um kernel relativamente recente), você pode saber se um processo está ignorando e/oumanuseioSIGINT observando a saída de
$ kill -l INT
2
$ grep Sig "/proc/$pid/status"
SigQ: 0/63858
SigPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000000000002
SigCgt: 0000000000000000
SIGINT é 2. O segundo bit de SigIgn acima é 1, o que significa que SIGINT é ignorado.
Você pode automatizar isso com:
$ SIG=$(kill -l INT) perl -lane 'print $1 if $F[0] =~ /^Sig(...):/ &&
$F[1] & (1<<($ENV{SIG}-1))' < "/proc/$pid/status"
Ign
Para verificar qual é o caractere atual intr
ou se isig
está habilitado para um determinado terminal:
$ stty -a < /dev/pts/0
[...] intr = ^C [...] isig
(acima do intr
caractere está ^C
(o caractere normalmente enviado pelo seu terminal (emulador) ao pressionar CTRL-Ce os sinais de entrada não são desabilitados.
$ stty -a < /dev/pts/1
[...] intr = ^K [...] -isig
( intr
o personagem está ^K
e isig
está desabilitado para /dev/pts/1
).
Para completar, existem duas outras maneiras pelas quais um processo pode fazer algo para parar de receber SIGINTs, embora isso não seja algo que você normalmente veria.
Após Ctrl+C, o sinal SIGINT é enviado para todos os processos dogrupo de processos em primeiro plano do terminal. Geralmente é o shell que coloca os processos em grupos de processos (mapeados para shellempregos) e diga ao dispositivo terminal qual é oprimeiro planoum.
Agora, um processo poderia:
Deixe seu grupo de processos. Se ele for movido para outro grupo de processos (qualquer grupo de processos, exceto aquele que é oprimeiro planoum), então ele não receberá mais o SIGINT Ctrl-C(nem os outros sinais relacionados ao teclado, como SIGTSTP, SIGQUIT). No entanto, ele poderia ser suspenso se tentasse ler (possivelmente escrever também, dependendo das configurações do dispositivo terminal) do dispositivo terminal (como fazem os processos em segundo plano).
Como um exemplo:
perl -MPOSIX -e 'setpgid(0,getppid) or die "$!"; sleep 10'
não poderia ser interrompível com Ctrl-C. Acima
perl
tentará ingressar no grupo de processos cujo ID é igual ao ID do processo pai. Em geral, não há garantia de que exista um grupo de processos com esse ID. Mas aqui, no caso desseperl
comando ser executado sozinho no prompt de um shell interativo, o ppid será o processo do shell e o shell normalmente terá sido iniciado em seu próprio grupo de processos.Se o comando ainda não for um líder de grupo de processos (o líder desse grupo de processos em primeiro plano), então iniciar um novo grupo de processos teria o mesmo efeito.
Por exemplo, dependendo do 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
teria o mesmo efeito.
ps
eperl
são iniciados no grupo de processos em primeiro plano, mas na maioria dos shells,ps
seria o líder desse grupo (como visto naps
saída acima, onde o pgid de ambosps
eperl
é o pid deps
), portanto,perl
pode iniciar seu próprio grupo de processos.Ou poderia alterar o grupo de processos em primeiro plano. Basicamente diga ao dispositivo tty para enviar o SIGINT para algum outro grupo de processosCtrl+C
perl -MPOSIX -e 'tcsetpgrp(0,getppid) or die$!; sleep 5'
Lá,
perl
permanece no mesmo grupo de processos, mas em vez disso informa ao dispositivo terminal que o grupo de processos em primeiro plano é aquele cujo ID é igual ao ID do processo pai (veja a nota acima sobre isso).