Lorsque vous appelez vfork()
, un nouveau processus est créé et ce nouveau processus emprunte l'image de processus du processus parent à l'exception de la pile. Le processus enfant reçoit une nouvelle étoile de pile, mais ne permet pas return
de la fonction qui a appelé vfork()
.
Pendant que l'enfant s'exécute, le processus parent est bloqué, car l'enfant a emprunté l'espace d'adressage du parent.
Peu importe ce que vous faites, tout ce qui accède à la pile ne modifie que la pile privée de l'enfant. Cependant, si vous modifiez des données globales, cela modifie les données communes et affecte donc également le parent.
Les choses qui modifient les données globales sont par exemple:
appeler malloc () ou gratuit ()
en utilisant stdio
modification des paramètres du signal
modification des variables qui ne sont pas locales à la fonction qui a appelé vfork()
.
...
Une fois que vous appelez _exit()
(important, ne jamais appeler exit()
), l'enfant est terminé et le contrôle est rendu au parent.
Si vous appelez une fonction de la exec*()
famille, un nouvel espace d'adressage est créé avec un nouveau code de programme, de nouvelles données et une partie de la pile du parent (voir ci-dessous). Une fois que cela est prêt, l'enfant n'emprunte plus l'espace d'adressage à l'enfant, mais utilise un propre espace d'adressage.
Le contrôle est rendu au parent, car son espace d'adressage n'est plus utilisé par un autre processus.
Important: sous Linux, il n'y a pas de véritable vfork()
implémentation. Linux implémente plutôt vfork()
basé sur le fork()
concept Copy on Write introduit par SunOS-4.0 en 1988. Afin de faire croire aux utilisateurs qu'ils utilisent vfork()
, Linux configure simplement les données partagées et suspend le parent pendant que l'enfant n'appelle pas _exit()
ou l'une des exec*()
fonctions.
Linux ne bénéficie donc pas du fait qu'un réel vfork()
n'a pas besoin de mettre en place une description de l'espace d'adressage pour l'enfant dans le noyau. Il en résulte un vfork()
qui n'est pas plus rapide que fork()
. Sur les systèmes qui implémentent un réel vfork()
, il est généralement 3 fois plus rapide fork()
et affecte les performances des shells qui utilisent vfork()
- ksh93
, le récent Bourne Shell
et le csh
.
La raison pour laquelle vous ne devriez jamais appeler exit()
de l' vfork()
enfant ed est qu'il exit()
vide stdio au cas où il y aurait des données non vidées de la période précédant l'appel vfork()
. Cela pourrait provoquer des résultats étranges.
BTW: posix_spawn()
est implémenté par-dessus vfork()
, vfork()
ne va donc pas être supprimé du système d'exploitation. Il a été mentionné que Linux n'utilise pas vfork()
pour posix_spawn()
.
Pour la pile, il y a peu de documentation, voici ce que dit la page de manuel Solaris:
The vfork() and vforkx() functions can normally be used the
same way as fork() and forkx(), respectively. The calling
procedure, however, should not return while running in the
child's context, since the eventual return from vfork() or
vforkx() in the parent would be to a stack frame that no
longer exists.
L'implémentation peut donc faire ce qu'elle veut. L'implémentation Solaris utilise la mémoire partagée pour le cadre de pile de l'appel de fonction vfork()
. Aucune implémentation n'accorde l'accès aux parties plus anciennes de la pile à partir du parent.