No Linux, o que acontece quando um programa (que possivelmente possui vários threads) recebe um sinal, como SIGTERM ou SIGHUP?
Qual thread intercepta o sinal? Vários threads podem obter o mesmo sinal? Existe um segmento especial dedicado inteiramente ao tratamento de sinais? Se não, o que acontece dentro do thread que vai tratar o sinal? Como a execução continua após a conclusão da rotina do manipulador de sinais?
Isso tem algumas nuances, com base na versão do kernel do Linux que você está usando.
Assumindo threads 2.6 posix, e se você estiver falando sobre o SO enviando SIGTERM ou SIGHUP, o sinal é enviado para o processo, que é recebido e tratado pelo thread raiz. Usando threads POSIX, você também pode enviar SIGTERM para threads individuais, mas suspeito que você esteja perguntando sobre o que acontece quando o sistema operacional envia o sinal para o processo.
No 2.6, o SIGTERM fará com que os threads filhos saiam "corretamente", enquanto no 2.4, os threads filhos foram deixados em um estado indeterminado.
E o que acontece dentro do thread raiz quando um sinal é recebido? Digamos que eu escrevi um manipulador de sinal personalizado para SIGUSR1 e agora estou enviando esse sinal para o processo. O thread raiz receberá esse sinal. Talvez esteja no meio de alguma função naquele momento. O que vai acontecer?
se você tiver um manipulador configurado, ele será tratado como uma interrupção, o fluxo do programa será interrompido e seu manipulador personalizado será executado. Uma vez executado, o controle retornará, assumindo que você não fez nada para alterar o fluxo normal (saída etc).
Observe que isso é específico para SIGUSR1, que IIRC não interrompe chamadas do sistema. Se você tentar fazer isso com o SIGINT, por exemplo, ele pode interromper a leitura de um fluxo e, quando você voltar a ler, o fluxo pode retornar um erro informando que foi interrompido.
Estou um pouco confuso sobre o que significa "thread raiz". Isso significa que o manipulador para SIGTERM sempre será executado no thread principal ou pode ser executado em qualquer thread?
— Stephen Nutt,
Esta resposta , que afirma que um thread arbitrário é escolhido para lidar com o sinal, contradiz sua resposta.
pthreads(7) descreve que POSIX.1 requer que todos os threads em um processo compartilhem atributos, incluindo:
disposições de sinal
POSIX.1 também requer que alguns atributos sejam distintos para cada thread, incluindo:
máscara de sinal ( pthread_sigmask(3))
pilha de sinal alternativo ( sigaltstack(2))
A complete_signalrotina do kernel Linux possui o seguinte bloco de código - os comentários são bastante úteis:
Então, você vê que você está no comando de onde os sinais são entregues:
Se o seu processo definiu a disposição de um sinal para SIG_IGNou SIG_DFL, então o sinal é ignorado (ou padrão - kill, core ou ignore) para todos os threads.
Se o seu processo definiu a disposição de um sinal para uma rotina de tratamento específica, então você pode controlar qual thread receberá os sinais, manipulando máscaras de sinal de thread específicas usando pthread_sigmask(3) . Você pode nomear um thread para gerenciar todos eles, ou criar um thread por sinal, ou qualquer mistura dessas opções para sinais específicos, ou você pode contar com o comportamento padrão atual do kernel Linux de entregar o sinal ao thread principal.
Alguns sinais, no entanto, são especiais de acordo com a signal(7)página do manual:
Um sinal pode ser gerado (e, portanto, pendente) para um processo como um todo (por exemplo, quando enviado usando kill (2) ) ou para uma thread específica (por exemplo, certos sinais, como SIGSEGV e SIGFPE, gerados como consequência da execução uma instrução específica em linguagem de máquina é direcionada por thread, assim como sinais direcionados a uma thread específica usando pthread_kill (3) ). Um sinal direcionado ao processo pode ser entregue a qualquer um dos threads que atualmente não tem o sinal bloqueado. Se mais de um dos encadeamentos tiver o sinal desbloqueado, o kernel escolhe um encadeamento arbitrário para o qual enviar o sinal.