Por que o Ctrl-C não funcionou?

8

Acabei de pressionar Ctrl c duas vezes no meu shell, na tentativa de interromper um processo que está demorando para terminar.

^C foi repetido duas vezes, mas o processo continuou em andamento.

Por que o Ctrl c não encerrou o processo como normalmente faz?

    
por themirror 26.09.2013 / 23:30

1 resposta

12

Os processos podem escolher:

  • ignora o sinal SIGINT normalmente enviado ao pressionar Ctrl-C (como com trap '' INT em um shell) ou tem seu próprio manipulador para ele que decide não terminar (ou falha em terminar em um atempadamente).
  • diz ao dispositivo de terminal que o caractere que faz com que uma SIGINT seja enviada para a tarefa em primeiro plano é outra coisa (como stty int '^K' em um shell)
  • diz ao dispositivo de terminal para não enviar nenhum sinal (como stty -isig em um shell).

Ou, eles podem ser ininterruptos, como no meio de uma chamada de sistema que não pode ser interrompida.

No Linux (com um kernel relativamente recente), você pode dizer se um processo está ignorando e / ou manipulando SIGINT, 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 do SigIgn acima é 1, o que significa que o 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 intr atual ou se isig está habilitado para um determinado terminal:

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

(acima do caractere intr é ^C (o caractere geralmente enviado pelo seu terminal (emulador) ao pressionar CTRL-C e os sinais de entrada não estão desativados.

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

(o caracter intr é ^K e isig está desativado para /dev/pts/1 ).

Para completar, há 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.

Sob Ctrl + C , o sinal SIGINT é enviado para todos os processos no grupo de processos em primeiro plano do terminal . Geralmente, é o shell que coloca os processos nos grupos de processos (mapeados para shell jobs ) e informam ao dispositivo de terminal qual é o primeiro plano .

Agora, um processo poderia:

  • Deixe seu grupo de processos. Se ele for movido para outro grupo de processos (qualquer grupo de processos, mas aquele que é o primeiro ), então ele não receberá mais o SIGINT em Ctrl-C (nem o outros sinais relacionados ao teclado, como SIGTSTP, SIGQUIT). Ele pode, no entanto, ser suspenso se tentar ler (possivelmente gravar também, dependendo das configurações do dispositivo terminal) do dispositivo terminal (como os processos em segundo plano).

    Como exemplo:

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

    não pode ser interrompido com Ctrl-C . Acima de perl tentará ingressar no grupo de processos cujo ID é igual ao ID do processo pai. Em geral, não há garantia de que exista tal grupo de processos com esse id. Mas aqui, no caso em que o comando perl é executado por conta própria 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 já não for um líder de grupo de processos (o líder desse grupo de processos em primeiro plano), a inicialização de um novo grupo de processos terá 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 e perl são iniciados no grupo de processos em primeiro plano, mas na maioria dos shells, ps seria o líder desse grupo (conforme visto na saída ps acima, em que o pgid de ps e perl é o pid de ps ), então perl pode iniciar seu próprio grupo de processos.

  • Ou pode alterar o grupo de processos de primeiro plano. Basicamente, diga ao dispositivo tty para enviar o SIGINT para algum outro grupo de processos no Ctrl + C

    perl -MPOSIX -e 'tcsetpgrp (0, getppid) ou morre $ !; dormir 5 '

    Lá, perl permanece no mesmo grupo de processos, mas está dizendo ao terminal que o grupo de processos em primeiro plano é aquele cujo ID é o mesmo que o ID do processo pai (consulte a observação acima sobre isso).

por 26.09.2013 / 23:35