O que faz com que vários sinais sejam enviados?

28

Às vezes fico um pouco confuso com todos os sinais que um processo pode receber. Pelo que entendi, um processo tem um manipulador padrão ( disposição do sinal ) para cada um desses sinais, mas pode fornecer seu próprio manipulador chamando sigaction().

Então, aqui está a minha pergunta: o que faz com que cada um dos sinais seja enviado? Sei que você pode enviar sinais manualmente para os processos em execução através do -sparâmetro kill, mas quais são as circunstâncias naturais sob as quais esses sinais são enviados? Por exemplo, quando é SIGINTenviado?

Além disso, existem restrições sobre quais sinais podem ser manipulados? Até SIGSEGVsinais podem ser processados ​​e o controle retornado ao aplicativo?

Nathan Osman
fonte
Uma resposta adequada para isso será épica e basicamente replicará as informações no artigo da Wikipedia sobre o assunto, então vou apenas apontar para lá.
Shawn J. Goff
@ Shawn: o artigo da Wikipedia tem uma lista de sinais, mas nenhuma apresentação clara de quem envia quais sinais.
Gilles 'SO- stop be evil'

Respostas:

41

Além da chamada de processos kill(2), alguns sinais são enviados pelo kernel (ou algumas vezes pelo próprio processo) em várias circunstâncias:

  • Os drivers de terminal enviam sinais correspondentes a vários eventos:
    • Notificações por pressionamento de tecla: SIGINT(volte ao loop principal) no Ctrl+ C, SIGQUIT(saia imediatamente) no Ctrl+ \, SIGTSTP(suspenda) no Ctrl+ Z. As chaves podem ser alteradas com o sttycomando
    • SIGTTINe SIGTTOUsão enviados quando um processo em segundo plano tenta ler ou gravar em seu terminal de controle.
    • SIGWINCH é enviado para sinalizar que o tamanho da janela do terminal mudou.
    • SIGHUPé enviado para o sinal de que o terminal tenha desaparecido (historicamente porque o seu modem tinha h ung -se , hoje em dia geralmente porque você fechou a janela do emulador de terminal).
  • Alguns traps de processador podem gerar um sinal. Os detalhes são dependentes da arquitetura e do sistema; Aqui estão exemplos típicos:
    • SIGBUS para uma memória de acesso não alinhada;
    • SIGSEGV para acessar uma página não mapeada;
    • SIGILL para uma instrução ilegal (código incorreto);
    • SIGFPEpara uma instrução de ponto flutuante com argumentos ruins (por exemplo sqrt(-1)).
  • Vários sinais notificam o processo de destino de que algum evento do sistema ocorreu:
    • SIGALRMnotifica que um cronômetro definido pelo processo expirou. Temporizadores podem ser configurados com alarm, setitimerentre outros.
    • SIGCHLD notifica um processo que um de seus filhos morreu.
    • SIGPIPEé gerado quando um processo tenta gravar em um canal quando o final da leitura é fechado (a idéia é que, se você executar foo | bare barsair, fooserá morto por a SIGPIPE).
    • SIGPOLL(também chamado SIGIO) notifica o processo que ocorreu um evento pesquisável. POSIX especifica eventos pesquisáveis ​​registrados através do I_SETSIG ioctl. Muitos sistemas permitem eventos pesquisáveis ​​em qualquer descritor de arquivo, definido através do O_ASYNC fcntlsinalizador. Um sinal relacionado é o SIGURGque notifica dados urgentes em um dispositivo (registrado via I_SETSIG ioctl) ou soquete .
    • Em alguns sistemas, SIGPWRé enviado a todos os processos quando o no- break sinaliza que uma falha de energia é iminente.

Essas listas não são exaustivas. Sinais padrão são definidos em signal.h.

A maioria dos sinais pode ser capturada e manipulada (ou ignorada) pelo aplicativo. Os únicos dois sinais portáteis que não podem ser capturados são SIGKILL(apenas morrer) e STOP(interromper a execução).

SIGSEGV( falha de segmentação ) e seu primo SIGBUS( erro de barramento ) podem ser detectados, mas é uma má idéia, a menos que você realmente saiba o que está fazendo. Um aplicativo comum para capturá-los é imprimir um rastreamento de pilha ou outras informações de depuração. Um aplicativo mais avançado é implementar algum tipo de gerenciamento de memória em processo ou interceptar instruções incorretas nos mecanismos das máquinas virtuais.

Finalmente, deixe-me mencionar algo que não é um sinal. Quando você pressiona Ctrl+ Dno início de uma linha em um programa que está lendo a entrada do terminal, isso indica ao programa que o final do arquivo de entrada foi atingido. Isso não é um sinal: é transmitido pela API de entrada / saída. Como Ctrl+ Ce amigos, a chave pode ser configurada com stty.

Gilles 'SO- parar de ser mau'
fonte
E SIGHUP, seu modem desligou. :-)
Keith
1
Outra coisa a ser observada SIGFPE:, de maneira não intuitiva, também é sinalizada no número inteiro dividido por zero e, às vezes, no excesso de número inteiro assinado.
ephemient
18

Para responder à sua segunda pergunta primeiro: SIGSTOPe SIGKILLnão pode ser capturado pelo aplicativo, mas todos os outros sinais podem, inclusive SIGSEGV. Essa propriedade é útil para depuração - por exemplo, com o suporte correto da biblioteca, você pode escutar SIGSEGVe gerar um backtrace de pilha para mostrar exatamente onde esse segfault aconteceu.

A palavra oficial (para o Linux, de qualquer maneira) sobre o que cada sinal faz está disponível digitando man 7 signalem uma linha de comando do Linux. http://linux.die.net/man/7/signal tem as mesmas informações, mas as tabelas são mais difíceis de ler.

No entanto, sem alguma experiência com sinais, é difícil saber pelas breves descrições o que eles fazem na prática, então aqui está minha interpretação:

Acionado pelo teclado

  • SIGINTacontece quando você bate CTRL+C.
  • SIGQUITé acionado por CTRL+\e despeja o núcleo.
  • SIGTSTPsuspende seu programa quando você bate CTRL+Z. Ao contrário SIGSTOP, é alcançável, o que dá aos programas via chance de redefinir o terminal para um estado seguro antes de se suspender.

Interações terminais

  • SIGHUP ("hangup") é o que acontece quando você fecha o xterm (ou desconecta o terminal) enquanto o programa está em execução.
  • SIGTTINe SIGTTOUpause seu programa se ele tentar ler ou gravar no terminal enquanto estiver em execução em segundo plano. Para SIGTTOUque isso aconteça, acho que o programa precisa estar gravando /dev/tty, não apenas o stdout padrão.

Acionado por uma exceção de CPU

Isso significa que seu programa tentou fazer algo errado.

  • SIGILLsignifica uma instrução ilegal ou desconhecida do processador. Isso pode acontecer se você tentar acessar as portas de E / S do processador diretamente, por exemplo.
  • SIGFPEsignifica que houve um erro de matemática no hardware; provavelmente o programa tentou dividir por zero.
  • SIGSEGV significa que seu programa tentou acessar uma região não mapeada da memória.
  • SIGBUSsignifica que o programa acessou a memória incorretamente de alguma outra maneira; Não entrarei em detalhes neste resumo.

Interação de processo

  • SIGPIPEacontece se você tentar gravar em um tubo depois que o leitor do tubo fechar sua extremidade. Veja man 7 pipe.
  • SIGCHLDacontece quando um processo filho que você criou fecha ou é suspenso (por SIGSTOPou semelhante).

Útil para auto-sinalização

  • SIGABRTgeralmente é causado pelo programa que chama a abort()função e causa um dump principal por padrão. Uma espécie de "botão de pânico".
  • SIGALRMé causado pela alarm()chamada do sistema, que fará com que o kernel entregue um SIGALRMprograma ao programa após um número especificado de segundos. Veja man 2 alarme man 2 sleep.
  • SIGUSR1e SIGUSR2são usados ​​como o programa gosta. Eles podem ser úteis para sinalizar entre processos.

Enviado pelo administrador

Esses sinais geralmente são enviados a partir do prompt de comandos, via killcomando, fgou bgno caso de SIGCONT.

  • SIGKILLe SIGSTOPsão os sinais desbloqueáveis. O primeiro sempre termina o processo imediatamente; o segundo suspende o processo.
  • SIGCONT retoma um processo suspenso.
  • SIGTERMé uma versão capturável de SIGKILL.
Jander
fonte
Qual sinal é enviado quando o shutdowncomando é usado?
Nathan Osman
Isso depende dos scripts de desligamento. Normalmente, SIGTERMé enviado primeiro, seguido por um atraso, seguido por SIGKILL. Em princípio, para um desligamento imediato e difícil, o kernel não precisa enviar nenhum sinal; poderia simplesmente parar de executar o processo.
Jander