Em sua página da web sobre o truque do autoduto , Dan Bernstein explica uma condição de corrida com select()
e sinaliza, oferece uma solução alternativa e conclui que
Obviamente, a coisa certa seria
fork()
retornar um descritor de arquivo, não um ID do processo.
O que ele quer dizer com isso - é algo sobre ser capaz de, select()
nos processos filhos, manipular suas alterações de estado, em vez de precisar usar um manipulador de sinal para ser notificado dessas alterações de estado?
signals
file-descriptors
fork
Lassi
fonte
fonte
signalfd
isso era algo naquela época?wait()
, havia coisas que você não podia fazer, então alguém inventou o SIGCHLD, mas foi um trabalho ruim. Na minha experiência, e agora que eles existem, polvilhando bom, não bloqueantewait3()
,wait4()
, e / ouwaitpid()
chamadas em lugares-chave (talvez o seu principal ciclo de eventos) é uma alternativa muito superior.Respostas:
O problema é descrito lá na sua fonte,
select()
deve ser interrompido por sinais comoSIGCHLD
, mas em alguns casos, não funciona tão bem. Portanto, a solução alternativa é ter gravação de sinal em um pipe, que é então observado porselect()
. Observar os descritores de arquivo é o queselect()
serve, para que ele resolva o problema.A solução alternativa transforma essencialmente o evento do sinal em um evento do descritor de arquivo. Se
fork()
apenas retornasse um fd em primeiro lugar, a solução alternativa não seria necessária, pois esse fd poderia presumivelmente ser usado diretamente comselect()
.Então, sim, sua descrição no último parágrafo parece correta para mim.
Outro motivo pelo qual um fd (ou algum outro tipo de identificador de kernel) seria melhor que um número de identificação de processo simples é que os PIDs podem ser reutilizados depois que o processo morre. Isso pode ser um problema em alguns casos, ao enviar sinais para processos, talvez não seja possível saber com certeza que o processo é o que você pensa que é e não outro reutilizando o mesmo PID. (Embora eu ache que isso não deve ser um problema ao enviar sinais para um processo filho, pois o pai precisa executar
wait()
o filho para que seu PID seja liberado.)fonte
wait()
.clone
, que é a chamada de sistema real que o fork chama no LInux. O sinalizador para ativar isso é chamadoCLONE_PIDFD
- Veja, por exemplo, lwn.net/Articles/784831 .É apenas uma reflexão sobre as linhas de "seria ótimo se o Unix tivesse um design diferente do que é".
O problema com os PIDs é que eles vivem em um espaço para nome global onde podem ser reutilizados para outro processo, e seria bom se
fork()
retornasse ao pai algum tipo de identificador que seria garantido que sempre se referisse ao processo filho e que poderia passar para outros processos via herança ou soquetes unix /SCM_RIGHTS
[1].Veja também a discussão aqui para um esforço recente para "consertar" isso no Linux, incluindo a adição de um sinalizador ao
clone()
qual fará com que ele retorne um pid-fd em vez de um PID.Mas mesmo assim, isso não eliminaria a necessidade desse hack de auto-pipe [2] ou de interfaces melhores, pois os sinais que notificam um processo pai sobre o estado de um filho não são os únicos que você gostaria de tratar no loop principal do programa. Infelizmente, coisas como
epoll(7) + signalfd(2)
no Linux oukqueue(2)
no BSD não são padrão - a única interface padrão (mas não suportada em sistemas mais antigos) é muito inferiorpselect(2)
.[1] Evitar que o PID seja reciclado novamente no momento em que o
waitpid()
syscall retornou e seu valor de retorno foi usado provavelmente poderia ser alcançado em sistemas mais recentes, usando-owaitid(.., WNOWAIT)
.[2] Eu não comentaria sobre o DJ Bernstein alegando que ele o inventou (desculpe a apofasia ;-)).
fonte
Bernstein não fornece muito contexto para esta observação "Right Thing", mas vou arriscar um palpite: ter fork (2) retornando um PID é inconsistente com open (2), creat (2) etc, retornando descritores de arquivo. O restante do sistema Unix poderia ter manipulado o processo com um descritor de arquivo representando um processo, em vez de um PID. Existe uma chamada de sistema signalfd (2) , que permite uma interação um pouco melhor entre sinais e descritores de arquivo, e mostra que um descritor de arquivo representando um processo pode funcionar.
fonte
pidfd_open
também no Linux, veja, por exemplo, lwn.net/Articles/789023