Estoy tratando de crear un demonio en python. He encontrado la siguiente pregunta , que tiene algunos buenos recursos que estoy siguiendo actualmente, pero tengo curiosidad por saber por qué es necesaria una doble bifurcación. Busqué en Google y encontré muchos recursos declarando que uno es necesario, pero no por qué.
Algunos mencionan que es para evitar que el demonio adquiera un terminal de control. ¿Cómo haría esto sin el segundo tenedor? ¿Cuáles son las repercusiones?
fork()
llamada devuelve el PID del niño al padre, por lo que es fácil obtener el PID del proceso hijo, pero no es tan fácil obtener el PID del proceso de nieto ).Respuestas:
Mirando el código al que se hace referencia en la pregunta, la justificación es:
Por lo tanto, es para asegurarse de que el demonio se vuelva a criar en init (solo en caso de que el proceso de inicio del demonio sea de larga duración) y elimine cualquier posibilidad de que el demonio recupere un tty de control. Entonces, si ninguno de estos casos se aplica, entonces una bifurcación debería ser suficiente. " Programación de red Unix - Stevens " tiene una buena sección sobre esto.
fuente
p=fork(); if(p) exit(); setsid()
. En este caso, el padre también sale y el proceso del primer hijo es reparentado. La magia de doble tenedor solo es necesaria para evitar que el demonio adquiera un tty.forks
unchild
proceso, este primer proceso secundario serásession leader
y podrá abrir un terminal TTY. Pero si vuelvo a bifurcar de este niño y termino este primer niño, el segundo niño bifurcado no serásession leader
y no podrá abrir una terminal TTY. ¿Es correcta esta afirmación?setsid()
. Entonces, el primer proceso bifurcado se convierte en un líder de sesión después de llamarsetsid()
y luego se bifurca nuevamente para que el proceso final de doble bifurcación ya no sea un líder de sesión. Aparte del requisito desetsid()
ser un líder de sesión, eres perfecto.Estaba tratando de entender el doble tenedor y me topé con esta pregunta aquí. Después de mucha investigación, esto es lo que descubrí. Con suerte, ayudará a aclarar mejor las cosas para cualquiera que tenga la misma pregunta.
En Unix cada proceso pertenece a un grupo que a su vez pertenece a una sesión. Aquí está la jerarquía ...
Sesión (SID) → Grupo de proceso (PGID) → Proceso (PID)
El primer proceso en el grupo de proceso se convierte en el líder del grupo de proceso y el primer proceso en la sesión se convierte en el líder de la sesión. Cada sesión puede tener un TTY asociado. Solo un líder de sesión puede tomar el control de un TTY. Para que un proceso sea realmente demonizado (ejecutado en segundo plano) debemos asegurarnos de que el líder de la sesión sea asesinado para que no haya posibilidad de que la sesión tome el control del TTY.
Ejecuté el programa de demonio de ejemplo Python de Sander Marechal desde este sitio en mi Ubuntu. Aquí están los resultados con mis comentarios.
Tenga en cuenta que el proceso es el líder de la sesión después
Decouple#1
, porque lo esPID = SID
. Todavía podría tomar el control de un TTY.Tenga en cuenta que
Fork#2
ya no es el líder de la sesiónPID != SID
. Este proceso nunca puede tomar el control de un TTY. Realmente demonizado.Personalmente, encuentro que la terminología fork-two es confusa. Un idioma mejor podría ser tenedor-desacoplador-tenedor.
Enlaces de interés adicionales:
fuente
fork()
ya evita la creación de zombies, siempre que cierre al padre.setsid()
antes de un sencillofork()
? En realidad, supongo que las respuestas de esta pregunta responden eso.Hablando estrictamente, el doble tenedor no tiene nada que ver con volver a criar al demonio como hijo de
init
. Todo lo que se necesita para volver a criar al hijo es que el padre debe salir. Esto se puede hacer con un solo tenedor. Además, hacer una doble bifurcación por sí solo no vuelve a crear el proceso del demonioinit
; los padres del demonio deben salir. En otras palabras, el padre siempre sale cuando se bifurca un demonio apropiado para que el proceso del demonio se vuelva a parearinit
.Entonces, ¿por qué el doble tenedor? POSIX.1-2008 La sección 11.1.3, " El terminal de control ", tiene la respuesta (énfasis agregado):
Esto nos dice que si un proceso de demonio hace algo como esto ...
... entonces el proceso del demonio podría adquirir
/dev/console
como su terminal de control, dependiendo de si el proceso del demonio es un líder de sesión, y dependiendo de la implementación del sistema. El programa puede garantizar que la llamada anterior no adquirirá un terminal de control si el programa primero asegura que no es un líder de sesión.Normalmente, cuando se inicia un demonio,
setsid
se llama (desde el proceso secundario después de llamarfork
) para disociar el demonio de su terminal de control. Sin embargo, llamarsetsid
también significa que el proceso de llamada será el líder de la sesión de la nueva sesión, lo que deja abierta la posibilidad de que el demonio pueda volver a adquirir un terminal de control. La técnica de doble tenedor garantiza que el proceso del demonio no sea el líder de la sesión, lo que garantiza que una llamada aopen
, como en el ejemplo anterior, no dará como resultado que el proceso del demonio vuelva a adquirir un terminal de control.La técnica del doble tenedor es un poco paranoica. Es posible que no sea necesario si sabe que el demonio nunca abrirá un archivo de dispositivo terminal. Además, en algunos sistemas puede no ser necesario incluso si el demonio abre un archivo de dispositivo terminal, ya que ese comportamiento está definido por la implementación. Sin embargo, una cosa que no está definida por la implementación es que solo un líder de sesión puede asignar el terminal de control. Si un proceso no es un líder de sesión, no puede asignar un terminal de control. Por lo tanto, si desea ser paranoico y estar seguro de que el proceso del demonio no puede adquirir accidentalmente un terminal de control, independientemente de los detalles específicos de la implementación, entonces la técnica de doble tenedor es esencial.
fuente
LogFile=/dev/console
. Los programas no siempre tienen control en tiempo de compilación sobre qué archivos pueden abrir;)Tomado de Bad CTK :
"En algunos sabores de Unix, se te obliga a hacer una doble bifurcación en el inicio, para entrar en modo demonio. Esto se debe a que no se garantiza que la bifurcación individual se separe del terminal de control".
fuente
setsid
después de una bifurcación inicial. Luego se asegura de que se mantenga separado de un terminal de control bifurcando nuevamente y haciendo que el líder de la sesión (el proceso que llamósetsid
) salga.fork
que se separe de la terminal de control. Essetsid
eso lo que hace. Perosetsid
fallará si se llama desde un líder de grupo de proceso. Por lo tanto, sefork
debe hacer una inicial antessetsid
para garantizar quesetsid
se llame desde un proceso que no sea un líder de grupo de procesos. El segundofork
asegura que el proceso final (el que será el demonio) no sea un líder de sesión. Solo los líderes de sesión pueden adquirir un terminal de control, por lo que esta segunda bifurcación garantiza que el demonio no volverá a adquirir un terminal de control sin darse cuenta. Esto es cierto para cualquier sistema operativo POSIX.Según "Programación avanzada en el entorno Unix", de Stephens y Rago, la segunda bifurcación es más una recomendación, y se hace para garantizar que el demonio no adquiera un terminal de control en los sistemas basados en el sistema V.
fuente
Una de las razones es que el proceso padre puede esperar inmediatamente_pid () para el hijo y luego olvidarse de él. Cuando el nieto muere, su padre es init, y lo esperará () y lo sacará del estado zombie.
El resultado es que el proceso padre no necesita estar al tanto de los niños bifurcados, y también hace posible bifurcar procesos de ejecución prolongada desde libs, etc.
fuente
La llamada daemon () tiene la llamada padre _exit () si tiene éxito. La motivación original puede haber sido permitir que el padre haga un trabajo extra mientras el niño está demonizando.
También puede basarse en una creencia errónea de que es necesario para garantizar que el demonio no tenga un proceso principal y esté reparentado para iniciar, pero esto sucederá de todos modos una vez que el padre muera en el caso de la bifurcación individual.
Así que supongo que todo se reduce a la tradición al final: un solo tenedor es suficiente siempre que el padre muera en poco tiempo de todos modos.
fuente
Parece que hay una discusión decente en http://www.developerweb.net/forum/showthread.php?t=3025
Citando a mlampkin desde allí:
fuente
Puede ser más fácil de entender de esta manera:
fuente