Em que ordem devo enviar sinais para processos de desligamento normal?

90

Em um comentário sobre esta resposta de outra pergunta , o comentador diz:

não use kill -9 a menos que seja absolutamente necessário! O SIGKILL não pode ser capturado, então o programa morto não pode executar nenhuma rotina de desligamento para, por exemplo, apagar arquivos temporários. Primeiro tente HUP (1), depois INT (2), depois SAIR (3)

Concordo em princípio sobre SIGKILL, mas o resto é novidade para mim. Dado que o sinal padrão enviado por killé SIGTERM, espero que seja o sinal mais comumente esperado para o desligamento normal de um processo arbitrário. Além disso, tenho visto isso SIGHUPusado por razões não encerradas, como dizer a um daemon "releia seu arquivo de configuração". E me parece que SIGINT(a mesma interrupção que você normalmente obteria com Ctrl-C, certo?) Não é tão amplamente suportada quanto deveria, ou termina de forma bastante desagradável.

Dado que SIGKILLé um último recurso - Quais sinais, e em que ordem , você deve enviar para um processo arbitrário, a fim de encerrá-lo o mais normalmente possível?

Por favor, fundamentar suas respostas com fatos de apoio (além de preferência pessoal ou opinião) ou referências, se você puder.

Nota: Estou particularmente interessado nas melhores práticas que incluem a consideração de bash / Cygwin.

Edit: Até agora, ninguém parece mencionar INT ou QUIT, e há uma menção limitada de HUP. Há alguma razão para incluí-los em um processo de eliminação ordenado?

PAUSA do sistema
fonte
4
Se você tiver que recorrer ao SIGKILL para realmente matar um processo, eu consideraria um bug no programa.
sigjuice

Respostas:

121

SIGTERM diz a um aplicativo para encerrar. Os outros sinais informam ao aplicativo outras coisas que não estão relacionadas ao encerramento, mas às vezes podem ter o mesmo resultado. Não use isso. Se você quiser que um aplicativo seja encerrado, diga para ele. Não dê sinais enganosos.

Algumas pessoas acreditam que a maneira padrão inteligente de encerrar um processo é enviando uma série de sinais, como HUP, INT, TERM e finalmente KILL. Isto é ridículo. O sinal certo para a finalização é o SIGTERM e se o SIGTERM não finalizar o processo instantaneamente, como você pode preferir, é porque o aplicativo escolheu tratar o sinal. O que significa que ele tem um bom motivo para não encerrar imediatamente: ele precisa de um trabalho de limpeza. Se você interromper o trabalho de limpeza com outros sinais, não há como dizer quais dados da memória ainda não foram salvos no disco, quais aplicativos cliente foram deixados pendurados ou se você os está interrompendo "no meio", o que é, efetivamente, corrupção de dados.

Para obter mais informações sobre o real significado dos sinais, consulte sigaction (2). Não confunda "Ação Padrão" com "Descrição", pois elas não são a mesma coisa.

SIGINT é usado para sinalizar uma "interrupção de teclado" interativa do processo. Alguns programas podem lidar com a situação de uma maneira especial para os usuários do terminal.

SIGHUP é usado para sinalizar que o terminal desapareceu e não está mais olhando para o processo. Isso é tudo. Alguns processos optam por encerrar em resposta, geralmente porque sua operação não faz sentido sem um terminal, alguns optam por fazer outras coisas, como verificar novamente os arquivos de configuração.

O SIGKILL é usado para remover o processo do kernel à força. É especial no sentido de que não é realmente um sinal para o processo, mas é interpretado diretamente pelo kernel.

Não envie SIGKILL. O SIGKILL certamente nunca deve ser enviado por scripts. Se o aplicativo manipular o SIGTERM, pode levar um segundo para limpar, pode demorar um minuto, pode levar uma hora . Dependendo do que o aplicativo precisa ser feito antes de estar pronto para terminar. Qualquer lógica que " presume " que a sequência de limpeza de um aplicativo tenha demorado o suficiente e precise ser atalho ou SIGKILL após X segundos está simplesmente errada .

A única razão pela qual um aplicativo precisaria de um SIGKILL para encerrar é se algo deu um bug durante sua sequência de limpeza. Nesse caso, você pode abrir um terminal e SIGKILL manualmente. Além disso, a única outra razão pela qual você SIGKILL algo é porque QUER evitar que ele se limpe sozinho.

Mesmo que metade do mundo envie SIGKILL cegamente após 5 segundos, ainda é uma coisa terrivelmente errada a se fazer.

lhunath
fonte
13
Você está certo quanto ao uso indevido de SIGKILL por aí. Mas há uma hora e um lugar para usá-lo, mesmo a partir de um script. Muitos, muitos aplicativos interceptam o SIGTERM e saem normalmente em menos de um segundo ou em apenas alguns segundos, e um deles ainda está em execução 30 segundos depois é porque está travado.
dwc
4
@dwc: tente deixá-lo rodar uma vez por uma hora. Se ele não morrer, ele está "preso" e conserte, ou seja preguiçoso e SIGKILL no futuro depois de algum tempo. Observe que você provavelmente está corrompendo coisas e lembre-se de que isso NÃO é algo que você deveria fazer "por padrão".
lhunath,
2
@lhunath: Espero que você não se importe, reorganizei seus parágrafos para tornar a resposta mais direta e clara a partir da pergunta. O discurso anti-SIGKILL é bom, mas um ponto secundário. Obrigado novamente por uma resposta excelente e educacional.
PAUSA do sistema
8
Não envie SIGKILL. Sempre. Simplesmente errado. Mesmo? Mesmo que seu sistema já esteja queimando graças a loops infinitos. Boa sorte. -1
konsolebox
//, votar positivamente para isso é ridículo.
Nathan Basanese de
18

Resposta curta : Enviar SIGTERM, 30 segundos depois SIGKILL,. Ou seja, mande SIGTERM, espere um pouco (pode variar de programa para programa, você pode conhecer melhor o seu sistema, mas de 5 a 30 segundos é o suficiente. Ao desligar uma máquina, você pode vê-la esperando automaticamente até 1min30s). Por que a pressa, afinal?), Então envie SIGKILL.

Resposta razoável : SIGTERM, SIGINT, SIGKILL Isto é mais do que suficiente. O processo muito provavelmente terminará antes SIGKILL.

Longa Resposta : SIGTERM, SIGINT, SIGQUIT, SIGABRT,SIGKILL

Isso é desnecessário, mas pelo menos você não está enganando o processo em relação à sua mensagem. Todos estes sinais não significa que você deseja que o processo de parar o que está fazendo e sair.

Não importa a resposta que você escolha nesta explicação, tenha isso em mente!

Se você enviar um sinal que significa outra coisa, o processo pode lidar com isso de maneiras muito diferentes (por um lado). Por outro lado, se o processo não manipular o sinal, não importa o que você envie, o processo será encerrado de qualquer maneira (quando a ação padrão é encerrar, é claro).

Portanto, você deve pensar como um programador. Você codificaria um manipulador de função para, digamos, SIGHUPencerrar um programa que se conecta a algo, ou faria um loop para tentar se conectar novamente? Essa é a principal questão aqui! É por isso que é importante apenas enviar sinais que significam o que você pretende.

Resposta longa quase estúpida :

A tabela abaixo contém os sinais relevantes e as ações padrão caso o programa não as manipule.

Eu os encomendei na ordem que sugiro usar (BTW, eu sugiro que você use a resposta razoável , não esta aqui), se você realmente precisar experimentar todos (seria divertido dizer que a mesa está ordenada em termos de a destruição que podem causar, mas isso não é totalmente verdade).

Os sinais com um asterisco (*) NÃO são recomendados. O importante é que você nunca sabe o que está programado para fazer. Especialmente SIGUSR! Pode iniciar o apocalipse (é um sinal gratuito para um programador fazer o que quiser!). Mas, se não for tratado OU no caso improvável de ser tratado para encerrar, o programa será encerrado.

Na tabela, os sinais com opções padrão para encerrar e gerar um core dump são deixados no final, um pouco antes SIGKILL.

Signal     Value     Action   Comment
----------------------------------------------------------------------
SIGTERM      15       Term    Termination signal
SIGINT        2       Term    Famous CONTROL+C interrupt from keyboard
SIGHUP        1       Term    Disconnected terminal or parent died
SIGPIPE      13       Term    Broken pipe
SIGALRM(*)   14       Term    Timer signal from alarm
SIGUSR2(*)   12       Term    User-defined signal 2
SIGUSR1(*)   10       Term    User-defined signal 1
SIGQUIT       3       Core    CONTRL+\ or quit from keyboard
SIGABRT       6       Core    Abort signal from abort(3)
SIGSEGV      11       Core    Invalid memory reference
SIGILL        4       Core    Illegal Instruction
SIGFPE        8       Core    Floating point exception
SIGKILL       9       Term    Kill signal

Então eu sugiro para esta longa resposta quase estúpido : SIGTERM, SIGINT, SIGHUP, SIGPIPE, SIGQUIT, SIGABRT,SIGKILL

E finalmente, o

Definitivamente estúpido, longa resposta longa :

Não tente isto em casa.

SIGTERM, SIGINT, SIGHUP, SIGPIPE, SIGALRM, SIGUSR2, SIGUSR1, SIGQUIT, SIGABRT, SIGSEGV, SIGILL, SIGFPEE se nada funcionou, SIGKILL.

SIGUSR2deve ser tentado antes SIGUSR1porque é melhor se o programa não lidar com o sinal. E é muito mais provável que funcione SIGUSR1se manipular apenas um deles.

BTW, o KILL : não é errado enviar SIGKILLpara um processo, como outra resposta afirmava. Bem, pense no que acontece quando você envia um shutdowncomando? Vou tentar SIGTERMe SIGKILLsó. Por que você acha que é o caso? E por que você precisa de quaisquer outros sinais, se o próprio shutdowncomando usa apenas esses dois?


Agora, de volta à resposta longa , esta é uma linha on-line interessante:

for SIG in 15 2 3 6 9 ; do echo $SIG ; echo kill -$SIG $PID || break ; sleep 30 ; done

Ele dorme por 30 segundos entre os sinais. Por que mais você precisaria de um oneliner ? ;)

Além disso, recomendado: experimente apenas com sinais 15 2 9da resposta razoável .

segurança : remova o segundo echoquando estiver pronto para ir. Eu chamo de meu dry-runpara onliners . Sempre use-o para testar.


Script kill graciosamente

Na verdade, fiquei tão intrigado com essa pergunta que decidi criar um pequeno script para fazer exatamente isso. Fique à vontade para fazer o download (clonar) aqui:

Link do GitHub para o repositório Killgracefully

DrBeco
fonte
8

Normalmente você enviaria SIGTERM, o padrão de matar. É o padrão por um motivo. Somente se um programa não for encerrado em um período de tempo razoável, você deverá recorrer a ele SIGKILL. Mas note que com SIGKILLo programa não há possibilidade de limpar as coisas e os dados podem ser corrompidos.

Quanto a SIGHUP, HUPsignifica "desligar" e, historicamente, significa que o modem foi desconectado. É essencialmente equivalente a SIGTERM. A razão que os daemons às vezes usam SIGHUPpara reiniciar ou recarregar a configuração é que os daemons se desconectam de quaisquer terminais de controle, pois um daemon não precisa deles e, portanto, nunca receberia SIGHUP, de modo que o sinal foi considerado como "liberado" para uso geral. Nem todos os daemons usam isso para recarregar! A ação padrão para SIGHUP é encerrar e muitos daemons se comportam dessa maneira! Então você não pode ir às cegas enviando SIGHUPs para daemons e esperando que eles sobrevivam.

Editar: SIGINT é provavelmente impróprio para encerrar um processo, já que normalmente está vinculado a ^Cou qualquer que seja a configuração do terminal para interromper um programa. Muitos programas capturam isso para seus próprios fins, portanto, é comum o suficiente para que não funcione. SIGQUITnormalmente tem o padrão de criar um dump de memória e, a menos que você queira arquivos de núcleo espalhados, também não é um bom candidato.

Resumo: se você enviar SIGTERMe o programa não morrer dentro do seu prazo, envie-o SIGKILL.

dwc
fonte
4
Observe que o acompanhamento com o SIGKILL deve ser feito apenas em situações em que desligar instantaneamente é uma prioridade mais alta do que evitar perda / corrupção de dados.
thomasrutter
@dwc Não entendi o seguinte ponto em sua resposta. poderia ajudar "A razão pela qual os daemons às vezes usam SIGHUP para reiniciar ou recarregar a configuração é que os daemons se desconectam de quaisquer terminais de controle e, portanto, nunca receberiam SIGTERM, de modo que o sinal foi considerado" liberado "para uso geral."
Jack
3
@Jack Deixe-me tentar: SIGHUP é o sinal de "desligar" que informa a um processo que o terminal foi desconectado. Como os daemons são executados em segundo plano, eles não precisam de terminais. Isso significa que um sinal de "desligar" não é relevante para os daemons. Eles nunca vão recebê-lo de uma desconexão de terminal, uma vez que eles não têm terminais conectados em primeiro lugar. E como o sinal é definido de qualquer maneira, embora eles não precisem dele para o propósito original, muitos daemons o usam para um propósito diferente, como reler seus arquivos de configuração.
PAUSA do sistema de
Obrigado sistema PAUSE. isso é útil.
Jack
7

SIGTERMna verdade, significa enviar uma mensagem a um aplicativo: " você seria tão gentil e cometeria suicídio ". Ele pode ser capturado e manipulado pelo aplicativo para executar o código de limpeza e encerramento.

SIGKILLnão pode ser capturado pelo aplicativo. O aplicativo é encerrado pelo sistema operacional sem nenhuma chance de limpeza.

É normal enviar SIGTERMprimeiro, dormir um pouco e depois enviar SIGKILL.

Vartec
fonte
Suponho que a votação seria um pouco mais eficiente do que dormir (antes do SIGKILL)
Ohad Schneider
Sim, seria @OhadSchneider, mas exigiria algo mais do que um simples comando bash.
vartec
Sim, acho que você precisaria fazer um loop enquanto o processo ainda está vivo usando algo como isto: stackoverflow.com/a/15774758/67824 .
Ohad Schneider
5
  • SIGTERM é equivalente a "clicar no 'X'" em uma janela.
  • SIGTERM é o que o Linux usa primeiro, quando está sendo encerrado.
gbarry
fonte
Isso é o que eu queria saber. +1. Obrigado.
Luc
6
"SIGTERM é equivalente a" clicar no 'X' "em uma janela" Não, não é, porque qualquer aplicativo pode abrir facilmente qualquer número de (documento e ferramenta, por exemplo) janelas, quanto mais diálogos, e não pode até mesmo responder a um último comando de fechamento de janela como faz a um comando de saída (não consigo pensar em nenhum exemplo óbvio, mas embora não seja óbvio, não há razão para que não possa ser feito dessa forma). SIGTERM é (ou deveria ser) equivalente a pedir gentilmente ao aplicativo para encerrar, no entanto , isso pode ser executado naquele aplicativo específico .
usuário
3

Com toda a discussão acontecendo aqui, nenhum código foi oferecido. Aqui está minha opinião:

#!/bin/bash

$pid = 1234

echo "Killing process $pid..."
kill $pid

waitAttempts=30 
for i in $(seq 1 $waitAttempts)
do
    echo "Checking if process is alive (attempt #$i / $waitAttempts)..."
    sleep 1

    if ps -p $pid > /dev/null
    then
        echo "Process $pid is still running"
    else
        echo "Process $pid has shut down successfully"
        break
    fi
done

if ps -p $pid > /dev/null
then
    echo "Could not shut down process $pid gracefully - killing it forcibly..."
    kill -SIGKILL $pid
fi
Ohad Schneider
fonte
0

HUP soa como lixo para mim. Eu o enviaria para obter um daemon para reler sua configuração.

SIGTERM pode ser interceptado; seus daemons podem ter um código de limpeza para executar quando receber esse sinal. Você não pode fazer isso por SIGKILL. Assim, com o SIGKILL você não está dando ao autor do daemon nenhuma opção.

Mais sobre isso na Wikipedia

innaM
fonte