Estou ciente de que, devido à reutilização de PID em kernels do tipo Unix, os sinais podem ser entregues ao processo errado se forem enviados após o PID já ter sido colhido.
A discussão do que segue provavelmente dependerá necessariamente do kernel específico que estamos discutindo, então estou feliz em reduzir o escopo para Linux. Embora eu receba respostas de especialistas em outros kernels.
Algumas situações a considerar:
Digamos que eu esteja no meio de uma chamada para
kill(2)
um processo zumbi (ou seja, já estou no espaço do kernel e executando o código do kernel para iniciar o sinal). Ao mesmo tempo, o pai do zumbi chamawait(2)
. É possível que minha chamadakill(2)
acabe tentando atuar em um processo diferente?Digamos que eu tenha
kill(2)
feito -ed (ou seja, retornei com sucesso da chamada ao espaço do usuário) um processo, mas antes que meu sinal possa ser entregue, um sinal diferente é capturado e mata o processo. Nesse caso, presumo que é garantido que meu sinal será destruído. Uma linha de raciocínio é: mesmo que o PID seja obtido e um processo diferente com o mesmo PID seja gerado simultaneamente, entregar o sinal ao novo processo pode abrir brechas de permissão.
Obrigado
Sim. Pode haver um período de tempo arbitrário entre um processo que emite a
kill
chamada do sistema e o ponto em que o kernel decide qual processo encerrar. Parte desse tempo é gasto no processo de preparação da chamada do sistema e parte desse tempo é gasto no kernel. A qualquer momento desse processamento, o kernel pode decidir mudar para a execução de algum outro thread (seja devido a uma interrupção ou porque o kernel tentou obter um bloqueio que já estava em uso). O processo em execuçãokill
e o processo em execuçãowait
podem ter as chamadas do sistema atendidas por processadores diferentes, portanto, eles podem até estar no modo kernel ao mesmo tempo.A
kill
chamada do sistema não tem muito o que fazer, portanto, uma interrupção não é muito provável. Mas isso pode acontecer, e acontecerá se você tentar várias vezes. E em um sistema multiprocessador, uma corrida é mais provável.Você pode ver como o kernel do Linux lida com uma chamada de sistema observando o código-fonte. Elixir fornece um visualizador online conveniente com referências cruzadas. A implementação do
kill
sinal começa comSYSCALL_DEFINE2(kill, …)
(o 2 é porque existem dois parâmetros). Como você pode ver, o código consiste em uma função muito curtaprepare_kill_siginfo
e depois no início da funçãokill_something_info
até o ponto em que essa função chamaread_lock(&tasklist_lock)
. Uma vez que a chamada retorna, nenhuma entrada pode ser adicionada ou removida da tabela de processos e, em particular, a entrada parapid
continua designando o mesmo processo, até que a chamada correspondente sejaread_unlock
imediatamente antes do retorno da função. Isso deixa apenas um tempo muito curto para que ocorram interrupções ou para outros processadores adquirirem o bloqueio da lista de tarefas primeiro, mas esse tempo não é e não pode ser zero.Alguns kernels, como o OpenBSD, evitam que um PID seja reutilizado logo após a destruição do objeto do processo. Isso torna a condição de corrida menos provável, possivelmente até impossível se o sistema estiver levemente carregado (se for apenas você no seu PC fazendo nada além de tentar executar dois processos). Mas a condição de corrida permanece possível se o sistema estiver suficientemente carregado (com muitos processos sendo criados e eliminados). Não há como impedir a corrida.
Devido ao potencial para uma corrida, o projeto de um software multiprocesso geralmente deve providenciar que os processos sejam gerenciados por seus pais, ou pelo menos pelo líder do grupo. O pai pode garantir que nunca tente encerrar um processo que já esteja aguardando.
Sim, uma vez que seu processo retornou da
kill
chamada do sistema, o kernel decidiu qual processo (ou processo zumbi) o sinal tem como alvo. É possível que o sinal ainda não tenha sido processado e nunca seja entregue se o alvo já for um zumbi. Mas o kernel escolhe para qual entrada da tabela de processos o sinal se destina durante a execução da chamada do sistema.