Estou usando o Ubuntu 14.04 e estou enfrentando esse comportamento que não consigo entender:
- Execute o
yes
comando (no shell padrão: Bash ) - Digite CtrlZpara parar
yes
- Corra
jobs
. Resultado:
[1]+ Stopped yes
- Corra
kill -9 %1
para pararyes
. Resultado:
[1]+ Stopped yes
- Corra
jobs
. Resultado:
[1]+ Stopped yes
Isso ocorre no Ubuntu 3.16.0-30-generic
rodando em uma máquina virtual paralela.
Por que meu kill -9
comando não encerrou o comando yes ? Eu pensei que SIGKILL não pode ser pego ou ignorado? E como posso terminar o comando yes ?
shell
job-control
s1m0n
fonte
fonte
uname -a
) pleaseLinux ubuntu 3.16.0-30-generic #40~14.04.1-Ubuntu SMP Thu Jan 15 17:43:14 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
. Estou executando o Ubuntu no Parallels Desktop.(signal)
para que você possa ver a diferença.Respostas:
Os sinais estão bloqueados para processos suspensos. Em um terminal:
Em um segundo terminal:
No primeiro terminal:
No entanto,
SIGKILL
não pode ser bloqueado. Fazer a mesma coisa comkillall -9 yes
o segundo terminal fornece isso imediatamente noyes
terminal:Consequentemente, se
kill -9 %1
não encerrar o processo imediatamente, vocêbash
não estará enviando o sinal atéfg
o processo ou você descobriu um bug no kernel.fonte
SIGTSTP
(que é a versão bloqueávelSIGSTOP
) para o processo ativo. Isso coloca o processo em um estado congelado, onde o kernel não o agenda. Isso também inibe o processamento do sinal (exceto oSIGCONT
sinal que descongela o processo) e, portanto, impede que o processo seja eliminado imediatamente.SIGTERM
está bloqueado, masSIGKILL
não está. De qualquer forma, de acordo com um comentário do OP, o problema parece ser quejobs
não detecta que o processo morreu, não o processo que não está sendo mortokill -9 %1
.SIGKILL
não possa ser bloqueado, não há garantia de que será entregue dentro de um período significativo. Se um processo for suspenso, a E / S de bloqueio pendente, por exemplo,SIGKILL
não chegará até que o processo seja ativado. Isso pode ser potencialmente nunca, se nenhuma E / S ocorrer.Não entre em pânico.
Não há nada estranho acontecendo. Não há bug do kernel aqui. Esse é um comportamento perfeitamente normal do shell Bourne Again e de um sistema operacional multitarefa.
É importante lembrar que um processo se mata , mesmo em resposta a
SIGKILL
. O que está acontecendo aqui é que o shell Bourne Again está lidando com as coisas antes do processo que ele acabou de dizer para se matar.Considere o que acontece a partir do ponto em
yes
que foi interrompidoSIGTSTP
e você acabou de executar okill
comando com o shell Bourne Again:SIGKILL
para oyes
processo.yes
processo está programado para ser executado e se mata imediatamente.O motivo pelo qual você está vendo uma coisa e outras pessoas estão vendo outra é uma corrida simples entre dois processos prontos para execução, cujo vencedor é inteiramente o que varia de máquina para máquina e ao longo do tempo. A carga do sistema faz a diferença, assim como o fato de sua CPU ser virtual.
No caso interessante, os detalhes da etapa 2 são os seguintes:
kill
comando interno, ele marca a entrada em sua tabela de tarefas como necessitando de uma mensagem de notificação impressa no próximo ponto disponível.kill
comando e, pouco antes de imprimir, o prompt verifica novamente se deve imprimir mensagens de notificação sobre algum trabalho.yes
processo ainda não teve a chance de se matar, portanto, no que diz respeito ao shell, o trabalho ainda está no estado parado. Portanto, o shell imprime uma linha de status de trabalho "Interrompido" para esse trabalho e redefine seu sinalizador de notificação pendente.yes
processo é agendado e se mata.Os pontos importantes são:
SIGKILL
não é mágico. Os processos verificam sinais pendentes ao retornar ao modo de aplicativo a partir do modo kernel, o que ocorre no final das falhas da página, interrupções (não aninhadas) e chamadas do sistema. A única coisa especial é que o kernel não permite que a ação em respostaSIGKILL
seja outra coisa senão suicídio imediato e incondicional, sem retorno ao modo de aplicativo. É importante ressaltar que os processos precisam estar fazendo transições do modo kernel para aplicativo e devem ser agendados para serem executados para responder a sinais.set -o notify
). Eles são impressos quando, em seguida, o shell atingir um ponto em seu ciclo de execução que verifica se há alguma notificação pendente.kill
e uma vez peloSIGCHLD
manipulador de sinal. Isso significa que é possível ver duas mensagens se o shell estiver executando antes doyes
processo ser remarcado para se matar; uma mensagem "Parada" e uma mensagem "Morto"./bin/kill
programa não tem acesso à tabela de tarefas internas do shell; então você não verá esse comportamento com/bin/kill
. O sinalizador pendente de notificação é definido apenas uma vez, peloSIGCHLD
manipulador.kill
oyes
processo for de outro shell.fonte
jobs
e o shell ainda vê o processo como vivo. Essa seria uma condição de corrida incomumente longa. :)jobs
comandos de multiplicação após oskill
quais todos ainda indicam que o processo está parado. Você, no entanto, me inspirou a continuar experimentando e eu descobri isso: a mensagem[1]+ Terminated yes
é impressa assim que eu executo outro comando externo (não um shell embutido comoecho
oujobs
). Para que eu possa executar ojobs
quanto quiser e ele continua imprimindo[1]+ Stopped yes
. Mas assim que eu corrols
por exemplo, impressões Bash[1]+ Terminated yes
jobs
não percebe que o processo realmente morreu ... Não sei o que fazer com o status sendo atualizado executando outro comando.Algo descolado pode estar acontecendo no seu sistema; no meu, sua receita funciona muito bem com e sem o
-9
:Receba o pid com
jobs -p
e tente matá-lo comoroot
.fonte
kill
comando interno do seu bash vá além e verifique se o trabalho está congelado (você pode tentar descobrir o PID do trabalho e matá-lo usandoenv kill <pid>
. Dessa forma, você usará okill
comando real e não o bash embutido.which kill /usr/bin/kill
which
não é um bash-builtin, porwhich <anything>
isso sempre fornecerá o caminho para o comando real. Mas tente compararkill --help
vs./usr/bin/kill --help
.kill
.O que você está observando é um bug nesta versão do bash.
kill -9 %1
mata o trabalho imediatamente. Você pode observar isso comps
. Você pode rastrear o processo bash para ver quando akill
chamada do sistema é chamada e rastrear o subprocesso para ver quando recebe e processa os sinais. Mais interessante, você pode ver o que está acontecendo com o processo.Em outro terminal:
O subprocesso é um zumbi . Está morto: tudo o que resta é uma entrada na tabela de processos (mas não há memória, código, arquivos abertos etc.). A entrada é deixada em aberto até que seu pai ou mãe notifique e recupere seu status de saída chamando a
wait
chamada de sistema ou um de seus irmãos .Um shell interativo deve verificar se há filhos mortos e colhê-los antes de imprimir um prompt (a menos que configurado de outra forma). Esta versão do bash falha ao fazê-lo em algumas circunstâncias:
Você pode esperar que o bash relate "Killed" assim que imprimir o prompt após o
kill
comando, mas isso não é garantido, porque há uma condição de corrida. Os sinais são entregues de forma assíncrona: akill
chamada do sistema retorna assim que o kernel descobre para quais processos entregar o sinal, sem esperar que ele seja realmente entregue. É possível, e acontece na prática, que o bash tenha tempo para verificar o status de seu subprocesso, descobrir que ele ainda não está morto (wait4
não relata nenhuma morte infantil) e imprimir que o processo ainda está parado. O que há de errado é que, antes do próximo prompt, o sinal foi entregue (ps
relata que o processo está morto), mas o bash ainda não foi chamadowait4
(podemos ver isso não apenas porque ele ainda relata o trabalho como "Parado", mas porque o zumbi ainda está presente na tabela de processos). De fato, o bash só colhe o zumbi na próxima vez que ele precisar chamarwait4
, quando executa algum outro comando externo.O bug é intermitente e eu não pude reproduzi-lo enquanto o bash é rastreado (presumivelmente porque é uma condição de corrida em que o bash precisa reagir rapidamente). Se o sinal é entregue antes das verificações do bash, tudo acontece como esperado.
fonte