Por que o Ctrl-C se comportaria diferentemente de matar -2?

6

Eu tenho um programa que deve manipular o SIGINT e desligar normalmente. Quando executo este programa a partir de um terminal sem precisar de fundo, posso desligá-lo usando Ctrl-C. Inspecionar os logs mostra que tudo funcionou como esperado.

Quando abro um terminal separado e chamo kill -2 [pid] ou kill -s INT [pid] , não faz nada. Não vejo nada nos logs e o programa continua a rodar como de costume até que eu pressione Ctrl-C no terminal em que o iniciei.

Existe alguma diferença entre como o Ctrl-C envia o sinal e como o kill faz?

Detalhes adicionais:

O programa em questão é um aplicativo Java iniciado por um script de shell bash que configura algumas variáveis de ambiente (a saber, CLASSPATH ) e, em seguida, chama java [main class] . Pressionar Ctrl-Z e, em seguida, executar ps resulta no seguinte:

$ ps -f
UID        PID  PPID  C STIME TTY          TIME CMD
mdeck    10251 10250  0 11:48 pts/2    00:00:00 -bash
mdeck    13405 10251  0 18:12 pts/2    00:00:00 /bin/bash /usr/local/bin/myapp.sh
mdeck    13509 13405 25 18:12 pts/2    00:00:03 java com.company.MyApp
mdeck    13526 10251  0 18:13 pts/2    00:00:00 ps -f

A saída de stty conforme solicitado por Gilles está abaixo:

$ stty -a </dev/pts/2
speed 38400 baud; rows 40; columns 203; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0;
-parenb -parodd cs8 -hupcl -cstopb cread -clocal -crtscts
-ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany -imaxbel -iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke
    
por Mike Deck 14.08.2012 / 00:32

2 respostas

5

Uma possibilidade é que o programa capture a seqüência Ctrl + C . Verifique a saída de stty -a ; a configuração intr indica qual combinação de teclas (se houver) envia um sinal SIGINT e isig indica se as chaves de sinal estão ativadas ( -isig significa que elas estão desativadas).

Se o programa consiste em vários processos, pressionar Ctrl + C envia SIGINT para todos os processos na grupo de processos . Você pode obter o mesmo efeito enviando o sinal para o grupo de processos, em vez de enviá-lo para um dos processos. Para enviar um sinal para um grupo de processos, primeiro determine seu líder: esse é o primeiro processo que inicia todos os outros; se você executar o grupo de processos em segundo plano, esse é o PID mostrado por jobs -l . O PID do líder do grupo de processos é o PGID (id do grupo de processos); envie o sinal para o negativo. Por exemplo. se o PGID for 1234, execute kill -INT -1234 .

Se o programa consistir em um script de wrapper e um aplicativo principal, há dois casos a serem considerados. Se não houver limpeza para fazer, para que o script wrapper termine assim que a aplicação principal terminar, faça a chamada do script de wrapper exec :

#!/bin/sh
export SOMEVAR=somevalue
…
exec /path/to/application "$@"

Desta forma, o aplicativo substitui o script, herdando seu PID. Alguns shells otimizam um script que termina executando outro programa, mas não todos. Essa abordagem não funciona quando o script precisa executar alguma limpeza, como a remoção de arquivos temporários.

Considere fazer o script detectar um sinal e transmitir o sinal para o aplicativo. Aqui está um esboço de como isso acontece:

/path/to/application "$@" &
app_pid=$!
trap -INT 'kill -INT $app_pid'
wait $!
rm /temp/file
    
por 14.08.2012 / 02:57
4

Com base nas perguntas feitas por @Gilles nos comentários à minha pergunta original, percebi que o comando kill -2 que eu estava enviando estava direcionando o pid do script wrapper que iniciou o aplicativo, em vez do processo que manipula o próprio sinal.

Usando os pids da minha pergunta, kill -s 13405 não estava sinalizando corretamente o aplicativo, mas chamar kill -s 13509 funciona como esperado.

Agora, minha pergunta é como posso atualizar meu script wrapper para propagar um SIGINT para seus processos filhos, mas criarei uma questão separada para isso.

    
por 14.08.2012 / 01:23

Tags