J'essaie de créer un démon en python. J'ai trouvé la question suivante , qui contient quelques bonnes ressources que je suis en train de suivre, mais je suis curieux de savoir pourquoi un double fork est nécessaire. J'ai fouillé dans Google et trouvé de nombreuses ressources indiquant que l'une d'elles est nécessaire, mais pas pourquoi.
Certains mentionnent qu'il s'agit d'empêcher le démon d'acquérir un terminal de contrôle. Comment ferait-il cela sans la deuxième fourchette? Quelles sont les répercussions?
En regardant le code référencé dans la question, la justification est la suivante:
# Fork a second child and exit immediately to prevent zombies. This
# causes the second child process to be orphaned, making the init
# process responsible for its cleanup. And, since the first child is
# a session leader without a controlling terminal, it's possible for
# it to acquire one by opening a terminal in the future (System V-
# based systems). This second fork guarantees that the child is no
# longer a session leader, preventing the daemon from ever acquiring
# a controlling terminal.
Il est donc important de s’assurer que le démon est redevenu parent sur init (juste au cas où le processus qui lève le démon est de longue durée), et élimine toute possibilité que le démon récupère un tty de contrôle. Donc, si aucun de ces cas ne s’applique, une fourchette devrait suffire. " Programmation réseau Unix - Stevens " contient une bonne section à ce sujet.
J'essayais de comprendre la double fourchette et suis tombé sur cette question ici. Après beaucoup de recherches, voici ce que j'ai découvert. J'espère que cela aidera à clarifier les choses pour tous ceux qui ont la même question.
Sous Unix, chaque processus appartient à un groupe qui appartient à son tour à une session. Voici la hiérarchie…
Session (SID) → Groupe de processus (PGID) → Processus (PID)
Le premier processus du groupe de processus devient le responsable du groupe de processus et le premier processus de la session devient le responsable de la session. Chaque session peut être associée à un téléscripteur. Seul un responsable de session peut prendre le contrôle d'un ATS. Pour qu'un processus soit véritablement démonisé (exécuté en arrière-plan), nous devons nous assurer que le responsable de la session est tué, de manière à ce que la session ne puisse jamais prendre le contrôle du TTY.
J'ai exécuté le programme exemple de démon python de Sander Marechal à partir de ce site sur mon Ubuntu. Voici les résultats avec mes commentaires.
1. `Parent` = PID: 28084, PGID: 28084, SID: 28046
2. `Fork#1` = PID: 28085, PGID: 28084, SID: 28046
3. `Decouple#1`= PID: 28085, PGID: 28085, SID: 28085
4. `Fork#2` = PID: 28086, PGID: 28085, SID: 28085
Notez que le processus est le responsable de la session après Decouple#1
, car il s'agit de PID = SID
. Il pourrait toujours prendre le contrôle d'un ATS.
Notez que Fork#2
n'est plus le leader de la session PID != SID
. Ce processus ne peut jamais prendre le contrôle d'un ATS. Vraiment démonisé.
Personnellement, je trouve la terminologie fourchette deux fois source de confusion. Un meilleur langage pourrait être fork-decouple-fork.
Liens supplémentaires d'intérêt:
Strictement parlant, le double-fork n’a rien à voir avec la redéfinition du rôle du démon en tant qu’enfant de init
. Tout ce qui est nécessaire pour redonner un parent à l'enfant est que le parent doit quitter. Cela peut être fait avec une seule fourche. De plus, faire un double fork en lui-même ne renvoie pas le processus de démon à init
; le parent du démon doit quitter. En d'autres termes, le parent quitte toujours lors de la conversion d'un démon approprié, de sorte que le processus de démon redevienne init
.
Alors pourquoi la double fourche? POSIX.1-2008 La section 11.1.3, " Le terminal de contrôle ", a la réponse (caractères gras ajoutés):
Le terminal de contrôle pour une session est attribué par le responsable de la session d'une manière définie par l'implémentation. Si un responsable de session n'a pas de terminal de contrôle et ouvre un fichier de terminal qui n'est pas déjà associé à une session sans utiliser l'option O_NOCTTY (voir open ()), il est défini par l'implémentation si le terminal devient le terminal de contrôle de la session. chef. Si un processus qui est pas un chef de session ouvre un fichier de terminal ou si l'option O_NOCTTY est utilisée sur open (), alors ce terminal ne deviendra pas le terminal de contrôle du processus appelant} .
Cela nous dit que si un processus démon fait quelque chose comme ça ...
int fd = open("/dev/console", O_RDWR);
... alors le processus démon pourrait acquérir /dev/console
en tant que terminal de contrôle, selon que le processus démon est ou non un meneur de session et en fonction de la mise en oeuvre du système. Le programme peut garantir que l'appel ci-dessus n'acquerra pas de terminal de contrôle si le programme garantit d'abord qu'il ne s'agit pas d'un leader de session.
Normalement, lors du lancement d'un démon, setsid
est appelé (à partir du processus enfant après l'appel fork
) pour dissocier le démon de son terminal de contrôle. Toutefois, l'appel de setsid
signifie également que le processus d'appel sera le responsable de la nouvelle session, ce qui laisse ouverte la possibilité que le démon puisse réacquérir un terminal de contrôle. La technique de double fork garantit que le processus démon n'est pas le leader de la session, ce qui garantit ensuite qu'un appel à open
, comme dans l'exemple ci-dessus, n'entraînera pas la réacquisition d'un terminal de contrôle par le processus démon.
La technique de la double fourche est un peu paranoïaque. Cela peut ne pas être nécessaire si vous savez que le démon n'ouvrira jamais un fichier de terminal. De plus, sur certains systèmes, cela peut ne pas être nécessaire même si le démon ouvre un fichier de terminal, car ce comportement est défini par l'implémentation. Cependant, une chose qui n'est pas définie par l'implémentation est que seul un leader de session peut allouer le terminal de contrôle. _ {Si un processus n'est pas un leader de session, il ne peut pas allouer de terminal de contrôle. Par conséquent, si vous voulez être paranoïaque et être certain que le processus démon ne peut pas acquérir par inadvertance un terminal de contrôle, quel spécificités définies par la mise en œuvre, la technique de la double fourche est essentielle.
Extrait de Bad CTK :
"Sur certaines versions d'Unix, vous êtes obligé d'effectuer un double-fork au démarrage, afin de passer en mode démon. En effet, le forking simple n'est pas garanti pour se détacher du terminal de contrôle."
Selon "Programmation avancée dans l'environnement Unix", de Stephens et Rago, le second fork est davantage une recommandation, et il est fait pour garantir que le démon n'acquiert pas de terminal de contrôle sur les systèmes basés sur System V.
Une des raisons est que le processus parent peut immédiatement wait_pid () pour l'enfant, puis l'oublier. Quand ensuite grand-enfant meurt, son parent est init et il l'attendra () et le retirera de l'état zombie.
Le résultat est que le processus parent n'a pas besoin de connaître les enfants fourchis et qu'il permet également de lancer des processus longs depuis les bibliothèques etc.
L'appel daemon () a l'appel parent _exit () s'il réussit. La motivation initiale était peut-être de permettre au parent de faire un travail supplémentaire pendant que l'enfant est en train de démoniser.
Cela peut également être basé sur une conviction erronée qu’il est nécessaire de s’assurer que le démon n’a pas de processus parent et qu’il est référencé comme il se doit, mais cela se produira quand même une fois que le parent sera mort dans l’affaire single fork.
Je suppose donc que tout se résume bien à la tradition: une seule fourchette suffit si le parent meurt peu de temps de toute façon.
Une discussion décente à ce sujet semble se trouver à http://www.developerweb.net/forum/showthread.php?t=3025
Citant mlampkin à partir de là:
... Pensez à l'appel setsid () comme la "nouvelle" façon de faire (dissocier du terminal) et au second appel fork () comme une redondance pour traiter la SVr4 ...
Il serait peut-être plus facile de comprendre de cette façon: