Para responder a essa pergunta, você precisa entender como os sinais são enviados para um processo e como existe um processo no kernel.
Cada processo é representado como um task_struct
dentro do kernel (a definição está no sched.h
arquivo de cabeçalho e começa aqui ). Essa estrutura contém informações sobre o processo; por exemplo, o pid. A informação importante está na linha 1566, onde o sinal associado é armazenado. Isso é definido apenas se um sinal for enviado ao processo.
Um processo morto ou um processo de zumbi ainda tem um task_struct
. A estrutura permanece até que o processo pai (natural ou por adoção) seja chamado wait()
após receber SIGCHLD
para colher seu processo filho. Quando um sinal é enviado, o signal_struct
é definido. Não importa se o sinal é captável ou não, neste caso.
Os sinais são avaliados sempre que o processo é executado. Ou para ser mais exato, antes de o processo seria executado. O processo está no TASK_RUNNING
estado. O kernel executa a schedule()
rotina que determina o próximo processo em execução de acordo com seu algoritmo de agendamento. Assumindo que esse processo é o próximo processo em execução, o valor de signal_struct
é avaliado, independentemente de haver um sinal de espera a ser tratado ou não. Se um manipulador de sinal for definido manualmente (via signal()
ou sigaction()
), a função registrada será executada, caso contrário a ação padrão do sinal será executada. A ação padrão depende do sinal que está sendo enviado.
Por exemplo, o SIGSTOP
manipulador padrão do sinal alterará o estado do processo atual para TASK_STOPPED
e depois será executado schedule()
para selecionar um novo processo a ser executado. Observe que SIGSTOP
não é alcançável (como SIGKILL
), portanto, não há possibilidade de registrar um manipulador de sinal manual. No caso de um sinal inacessível, a ação padrão será sempre executada.
Para sua pergunta:
Um processo desativado ou inoperante nunca será determinado pelo planejador como estando no TASK_RUNNING
estado novamente. Portanto, o kernel nunca executará o manipulador de sinal (padrão ou definido) para o sinal correspondente, seja qual for o sinal. Portanto, o exit_signal
nunca será definido novamente. O sinal é "entregue" ao processo, definindo o signal_struct
no task_struct
do processo, mas nada mais vai acontecer, porque o processo nunca vai ficar novamente. Não há código para executar, tudo o que resta do processo é essa estrutura do processo.
No entanto, se o processo pai colhe seus filhos wait()
, o código de saída que recebe é aquele em que o processo "inicialmente" morreu. Não importa se há um sinal aguardando para ser tratado.
kill
próprio comando retorna 0 ou 1?Um processo de zumbi já está basicamente morto. A única coisa é que ninguém reconheceu sua morte ainda; portanto, continua ocupando uma entrada na tabela de processos e um bloco de controle (a estrutura que o kernel do Linux mantém para cada encadeamento em atividade). Outros recursos, como bloqueios obrigatórios em arquivos, segmentos de memória compartilhada, semáforos etc., são recuperados.
Você não pode sinalizá-los porque ninguém pode agir sobre esse sinal. Até sinais fatais como KILL são inúteis, pois o processo já terminou sua execução. Você pode tentar:
Aqui, inicio um processo que bifurca e dorme antes de esperar pelo filho. A criança não faz nada além de dormir um pouco. Você pode matar a criança quando ela estiver dormindo ou logo após sair para ver a diferença:
fonte
ruby -e "loop while fork { exit! }"
... imgur.com/SoRXErm