Estou tentando criar um daemon em python. Encontrei a seguinte pergunta , que possui alguns bons recursos que estou seguindo atualmente, mas estou curioso para saber por que um garfo duplo é necessário. Eu procurei no google e encontrei muitos recursos declarando que um é necessário, mas não o porquê.
Alguns mencionam que é para impedir que o daemon adquira um terminal de controle. Como isso seria feito sem o segundo garfo? Quais são as repercussões?
fork()
chamada retorna o PID da criança ao pai, por isso é fácil obter o PID do processo filho, mas não é tão fácil obter o PID do processo do neto ).Respostas:
Observando o código referenciado na pergunta, a justificativa é:
Portanto, é para garantir que o daemon seja reinicializado no init (apenas no caso de o processo iniciar o daemon durar muito) e remove qualquer chance de o daemon recuperar um tty de controle. Portanto, se nenhum desses casos se aplicar, um garfo deverá ser suficiente. " Unix Network Programming - Stevens " tem uma boa seção sobre isso.
fonte
p=fork(); if(p) exit(); setsid()
. Nesse caso, o pai também sai e o processo do primeiro filho é reparado. A mágica de garfo duplo é necessária apenas para impedir que o daemon adquira um tty.forks
umchild
processo, esse primeiro processo filho será umsession leader
e poderá abrir um terminal TTY. Mas se eu retirar novamente esse filho e terminar este primeiro filho, o segundo filho bifurcado não será umsession leader
e não poderá abrir um terminal TTY. Esta afirmação está correta?setsid()
. Portanto, o primeiro processo bifurcado se torna um líder de sessão após a chamadasetsid()
e depois bifurcamos novamente para que o processo final de bifurcação não seja mais um líder de sessão. Além do requisito desetsid()
ser um líder de sessão, você está no local.Eu estava tentando entender o garfo duplo e me deparei com essa pergunta aqui. Depois de muita pesquisa, foi isso que eu descobri. Espero que ajude a esclarecer melhor as coisas para quem tem a mesma pergunta.
No Unix, todo processo pertence a um grupo que, por sua vez, pertence a uma sessão. Aqui está a hierarquia…
Sessão (SID) → Grupo de processos (PGID) → Processo (PID)
O primeiro processo no grupo de processos se torna o líder do grupo de processos e o primeiro processo na sessão se torna o líder da sessão. Cada sessão pode ter um TTY associado a ela. Somente um líder de sessão pode assumir o controle de um TTY. Para que um processo seja verdadeiramente daemonizado (executado em segundo plano), devemos garantir que o líder da sessão seja morto para que não haja possibilidade da sessão assumir o controle do TTY.
Executei o programa de daemon de exemplo python de Sander Marechal neste site no meu Ubuntu. Aqui estão os resultados com meus comentários.
Observe que o processo é o líder da sessão depois
Decouple#1
, porque éPID = SID
. Ainda poderia assumir o controle de um TTY.Observe que
Fork#2
não é mais o líder da sessãoPID != SID
. Esse processo nunca pode assumir o controle de um TTY.Verdadeiramente daemonized.Pessoalmente, acho que a terminologia é duas vezes confusa. Um idioma melhor pode ser garfo-desacoplamento-garfo.
Links adicionais de interesse:
fonte
fork()
já impede a criação de zumbis, desde que você feche o pai.setsid()
antes de um singlefork()
? Na verdade, acho que as respostas dessa pergunta respondem a isso.Estritamente falando, a bifurcação dupla não tem nada a ver com re-criação do daemon como filho de
init
. Tudo o que é necessário para re-pai do filho é que ele deve sair. Isso pode ser feito com apenas um único garfo. Além disso, fazer uma bifurcação por si só não reinicia o processo daemoninit
; o pai do daemon deve sair. Em outras palavras, o pai sempre sai quando bifurca um daemon adequado, para que o processo do daemon seja re-paiinit
.Então, por que o garfo duplo? A Seção 11.1.3 do POSIX.1-2008 , " O terminal de controle ", tem a resposta (ênfase adicionada):
Isso nos diz que, se um processo daemon fizer algo assim ...
... o processo daemon pode adquirir
/dev/console
como seu terminal de controle, dependendo se o processo daemon é um líder de sessão e dependendo da implementação do sistema. O programa pode garantir que a chamada acima não adquira um terminal de controle se o programa primeiro garantir que não é um líder de sessão.Normalmente, ao iniciar um daemon,
setsid
é chamado (do processo filho após a chamadafork
) para dissociar o daemon do seu terminal de controle. No entanto, chamarsetsid
também significa que o processo de chamada será o líder da nova sessão, o que deixa em aberto a possibilidade de o daemon recuperar novamente um terminal de controle. A técnica de bifurcação dupla garante que o processo daemon não seja o líder da sessão, o que garante que uma chamada paraopen
, como no exemplo acima, não resultará no processo daemon recuperando um terminal de controle.A técnica de garfo duplo é um pouco paranóica. Pode não ser necessário se você souber que o daemon nunca abrirá um arquivo de dispositivo do terminal. Além disso, em alguns sistemas, pode não ser necessário, mesmo que o daemon abra um arquivo de dispositivo do terminal, pois esse comportamento é definido pela implementação. No entanto, uma coisa que não é definida pela implementação é que apenas um líder de sessão pode alocar o terminal de controle. Se um processo não for um líder de sessão, ele não poderá alocar um terminal de controle. Portanto, se você deseja ser paranóico e ter certeza de que o processo daemon não pode adquirir inadvertidamente um terminal de controle, independentemente de quaisquer especificações definidas pela implementação, a técnica de bifurcação dupla é essencial.
fonte
LogFile=/dev/console
. Programas nem sempre têm o controle em tempo de compilação sobre quais arquivos eles podem abrir;)Retirado de Bad CTK :
"Em alguns tipos de Unix, você é forçado a fazer um garfo duplo na inicialização, para entrar no modo daemon. Isso ocorre porque não é garantido que o garfo único se solte do terminal de controle."
fonte
setsid
após um fork inicial. Em seguida, garante que ele permaneça desconectado de um terminal de controle, bifurcando-o novamente e fazendo com que o líder da sessão (o processo que chamousetsid
) saia.fork
que se desconecta do terminal de controle. Ésetsid
isso que faz. Massetsid
falhará se for chamado de um líder de grupo de processos. Portanto, uma inicialfork
deve ser feita antessetsid
para garantir quesetsid
seja chamada de um processo que não seja um líder de grupo de processos. O segundofork
garante que o processo final (aquele que será o daemon) não seja um líder de sessão. Somente os líderes da sessão podem adquirir um terminal de controle, portanto, este segundo garfo garante que o daemon não recupere inadvertidamente um terminal de controle. Isso vale para qualquer sistema operacional POSIX.De acordo com a "Programação Avançada no Ambiente Unix", de Stephens e Rago, a segunda bifurcação é mais uma recomendação e é feita para garantir que o daemon não adquira um terminal de controle em sistemas baseados no System V.
fonte
Uma razão é que o processo pai pode esperar wait_pid () imediatamente pelo filho e esquecê-lo. Quando o neto morre, seu pai é init, e espera () por isso - e tira-o do estado de zumbi.
O resultado é que o processo pai não precisa estar ciente dos filhos bifurcados e também possibilita a bifurcação de processos de execução longa de bibliotecas etc.
fonte
A chamada daemon () possui a chamada pai _exit () se for bem-sucedida. A motivação original pode ter sido permitir que os pais realizassem algum trabalho extra enquanto a criança daemonizava.
Também pode ser baseado em uma crença equivocada de que é necessário para garantir que o daemon não tenha processo pai e seja reparado para iniciar - mas isso acontecerá assim que o pai morrer no caso de garfo único.
Portanto, suponho que tudo se resume à tradição no final - um único garfo é suficiente desde que o pai morra em pouco tempo de qualquer maneira.
fonte
Uma discussão decente sobre isso parece estar em http://www.developerweb.net/forum/showthread.php?t=3025
Citando mlampkin a partir daí:
fonte
Pode ser mais fácil entender dessa maneira:
fonte