vfork
Section: System Calls (2)
Updated: 5 février 2023
Index
Return to Main Contents
NOM
vfork - Créer un processus enfant et bloquer le parent
BIBLIOTHÈQUE
Bibliothèque C standard (libc, -lc)
SYNOPSIS
#include <unistd.h>
pid_t vfork(void);
Exigences de macros de test de fonctionnalités pour la glibc (consulter
feature_test_macros(7)) :
vfork() :
Depuis la glibc 2.12 :
(_XOPEN_SOURCE >= 500) && ! (_POSIX_C_SOURCE >= 200809L)
|| /* Depuis la glibc 2.19 : */ _DEFAULT_SOURCE
|| /* glibc <= 2.19 : */ _BSD_SOURCE
Avant la glibc 2.12 :
_BSD_SOURCE || _XOPEN_SOURCE >= 500
DESCRIPTION
Description des normes
(D'après POSIX.1). La routine vfork() a le même effet que fork(2),
sauf que le comportement est indéfini si le processus créé par vfork()
effectue l'une des actions suivantes avant d'appeler avec succès _exit(2)
ou une routine de la famille exec(3) : modification d'une donnée autre
que la variable de type pid_t stockant le retour de vfork(), revenir
de la fonction dans laquelle vfork() a été invoqué, appel d'une autre
fonction.
Description de l'implémentation Linux
vfork(), tout comme fork(2), crée un processus enfant à partir du
processus appelant. Pour plus de détails sur les valeurs renvoyées et les
erreurs possibles, consultez fork(2).
vfork() est conçu comme un cas particulier de clone(2). Il sert à
créer un nouveau processus sans effectuer de copie de la table des pages
mémoire du processus parent. Cela peut être utile dans des applications
nécessitant une grande rapidité d'exécution, si l'enfant doit invoquer
immédiatement un appel execve(2).
vfork() diffère de fork(2) en ce que le thread appelant reste suspendu
jusqu'à ce que l'enfant se termine (soit normalement, en appelant
_exit(2), soit de façon anormale après l'envoi d'un signal fatal) ou
qu'il appelle execve(2). Jusqu'à ce point, l'enfant partage toute la
mémoire avec son parent, y compris la pile. Le processus enfant ne doit pas
revenir de la fonction en cours, ni appeler exit(3) (ce qui aurait pour
effet d'appeler les gestionnaires de sortie établis par le processus parent
et de vider les tampons stdio(3) du parent), mais appeler à _exit(2).
Comme avec fork(2), le processus enfant créé par vfork() hérite des
copies de plusieurs attributs du processus appelant (par exemple les
descripteurs de fichiers, les dispositions des signaux et le répertoire de
travail actuel) ; l'appel vfork() diffère seulement par le traitement de
l'espace d'adressage virtuel, comme décrit ci-dessus.
Les signaux pour le processus parent sont délivrés après que l'enfant libère
la mémoire du parent (c'est-à-dire après que l'enfant se termine ou qu'il
appelle execve(2)).
Description historique
Sous Linux, fork(2) est implémenté en utilisant un mécanisme de copie en
écriture, ainsi ses seuls coûts sont le temps et la mémoire nécessaire pour
dupliquer la table des pages mémoire du processus parent, et créer une
seulestructure de tâche pour l'enfant. Toutefois, jadis fork(2)
nécessitait malheureusement une copie complète de l'espace de données du
parent, souvent inutilement, car un appel exec(3) est souvent réalisé
immédiatement par l'enfant. Pour améliorer les performances, BSD a introduit
un appel système vfork() qui ne copie pas l'espace d'adressage du parent,
mais emprunte au parent son espace d'adressage et son fil de contrôle
jusqu'à un appel à execve(2) ou qu'une sortie survienne. Le processus
parent était suspendu tant que l'enfant utilisait les
ressources. L'utilisation de vfork() était loin d'être facile, car, pour
éviter de modifier les données du processus parent, il fallait être capable
de déterminer quelles variables se trouvaient dans des registres du
processeur.
STANDARDS
4.3BSD, POSIX.1-2001 (mais la déclare obsolète). POSIX.1-2008 supprime la
spécification de vfork().
Les exigences que les normes apportent sur vfork() sont plus relâchées
que celles sur fork(2), ainsi il est possible d'avoir une implémentation
conforme où les deux appels sont synonymes. En particulier, un programmeur
ne doit pas s'appuyer sur le fait que le parent reste bloqué jusqu'à ce que
l'enfant se termine ou appelle execve(2), ni sur le comportement par
rapport à la mémoire partagée.
NOTES
Certaines personnes considèrent la sémantique de vfork() comme une verrue
architecturale, et la page de manuel de 4.2BSD indique que « cet appel
système sera supprimé quand des mécanismes de partage appropriés seront
implémentés. Il ne faut pas essayer de tirer profit du partage mémoire
induit par vfork(), car dans ce cas il serait rendu synonyme de
fork(2) ». Cependant, même si le matériel de gestion mémoire moderne a
diminué la différence de performances entre fork(2) et vfork(), il
existe diverses raisons pour lesquelles Linux et d'autres systèmes ont
conservé vfork() :
- •
-
Certaines applications de haute performance ont besoin du petit gain apporté
par vfork().
- •
-
vfork() peut être implémenté sur des systèmes sans unité de gestion
mémoire (MMU, pour « memory-management unit »), mais fork(2) ne peut
pas être implémenté sur de tels systèmes (POSIX.1-2008 a supprimé vfork()
de la norme ; la raison invoquée par POSIX pour la fonction
posix_spawn(3) note que cette fonction, qui fournit une fonctionnalité
équivalente à fork(2)+exec(3), est conçue pour être implémentable sur
des systèmes sans MMU).
- •
-
Sur les systèmes où la mémoire est restreinte, vfork évite le besoin
d'allouer de la mémoire temporairement (voir la description de
/proc/sys/vm/overcommit_memory dans proc(5)) afin d'exécuter un
nouveau programme. Cela peut être particulièrement bénéfique lorsqu'un grand
processus parent souhaite exécuter un petit programme d'assistance dans un
processus enfant. Par contraste, l'utilisation de fork(2) dans ce
scénario nécessite soit l'allocation d'une quantité de mémoire égale à la
taille du processus parent (si la gestion stricte du dépassement est en
cours) soit un dépassement de mémoire avec le risque qu'un processus soit
terminé par la mise à mort sur mémoire saturée (OOM killer).
Mises en garde
Le processus enfant devrait veiller à ne pas modifier la mémoire d'une
manière inattendue, dans la mesure où les modifications seront vues par le
processus parent une fois que l'enfant s'est achevé ou exécute un autre
programme. À cet égard, les gestionnaires de signaux peuvent être
particulièrement problématiques : si un gestionnaire de signal qui est
invoqué dans l'enfant d'un vfork() modifie la mémoire, ces modifications
peuvent aboutir à une inconsistance de l'état du processus du point de vue
du processus parent (par exemple, les modifications de la mémoire pourraient
être visibles dans le parent, mais pas les modifications de l'état des
descripteurs de fichiers ouverts).
Lorsque vfork() est appelé dans un processus multithreadé, seul le thread
appelant est suspendu jusqu'à ce que l'enfant s'achève ou exécute un nouveau
programme. Cela signifie que l'enfant partage un espace d'adresses avec un
autre code en cours d'exécution. Cela peut être dangereux si un autre thread
dans le processus parent modifie son identifiant (avec setuid(2) ou une
autre commande similaire), dans la mesure où il y a alors deux processus
avec différents niveaux de privilèges exécutés dans le même espace
d'adresses. Comme exemple de risque, imaginez qu'un programme multithreadé
exécuté en tant que superutilisateur crée un enfant avec vfork(). Après
le vfork(), un thread dans le processus parent transfère le processus à
un utilisateur non privilégié afin d'exécuter du code non sûr (par exemple,
peut-être au moyen d'un greffon ouvert avec dlopen(3)). Dans ce cas, des
attaques sont possibles où le processus parent utilise mmap(2) pour
projeter en mémoire du code qui sera exécuté par le processus enfant
privilégié.
Notes pour Linux
Les gestionnaires enregistrés avec pthread_atfork(3) ne sont pas appelés
lorsqu'un programme multithreadé utilisant la bibliothèque de threads NPTL
appelle vfork(). En revanche ces gestionnaires sont appelés si le
programme utilise la bibliothèque LinuxThreads. (Consultez pthreads(7)
pour une description des bibliothèques de threads pour Linux.)
Un appel à vfork() est équivalent à appeler clone(2) avec flags
valant :
CLONE_VM | CLONE_VFORK | SIGCHLD
Historique
L'appel système vfork() est apparu dans 3.0BSD. Dans 4.4BSD, il est
devenu synonyme de fork(2), mais NetBSD l'a réintroduit à nouveau
(consultez
). Sous
Linux, il a été l'équivalent de fork(2) jusqu'à Linux 2.2.0-pre-6. Depuis
Linux 2.2.0-pre-9 (sur i386, un peu plus tard sur d'autres architectures),
il s'agit d'un appel système indépendant. La prise en charge a été
introduite dans la glibc 2.0.112.
BOGUES
Les détails de la gestion des signaux sont compliqués et varient suivant les
systèmes. La page de manuel BSD indique : « Pour éviter une possible
situation d'interblocage, les processus qui sont des enfants au milieu d'un
vfork() ne reçoivent jamais le signal SIGTTOU ou SIGTTIN ; des
sorties et des ioctl sont autorisés, mais des tentatives de lecture
donneront une indication de fin de fichier. »
VOIR AUSSI
clone(2), execve(2), _exit(2), fork(2), unshare(2),
wait(2)
TRADUCTION
La traduction française de cette page de manuel a été créée par
Christophe Blaess <https://www.blaess.fr/christophe/>,
Stéphan Rafin <stephan.rafin@laposte.net>,
Thierry Vignaud <tvignaud@mandriva.com>,
François Micaux,
Alain Portal <aportal@univ-montp2.fr>,
Jean-Philippe Guérard <fevrier@tigreraye.org>,
Jean-Luc Coulon (f5ibh) <jean-luc.coulon@wanadoo.fr>,
Julien Cristau <jcristau@debian.org>,
Thomas Huriaux <thomas.huriaux@gmail.com>,
Nicolas François <nicolas.francois@centraliens.net>,
Florentin Duneau <fduneau@gmail.com>,
Simon Paillard <simon.paillard@resel.enst-bretagne.fr>,
Denis Barbier <barbier@debian.org>,
David Prévot <david@tilapin.org>
et
Jean-Pierre Giraud <jean-pierregiraud@neuf.fr>
Cette traduction est une documentation libre ; veuillez vous reporter à la
GNU General Public License version 3
concernant les conditions de copie et
de distribution. Il n'y a aucune RESPONSABILITÉ LÉGALE.
Si vous découvrez un bogue dans la traduction de cette page de manuel,
veuillez envoyer un message à
Index
- NOM
-
- BIBLIOTHÈQUE
-
- SYNOPSIS
-
- DESCRIPTION
-
- Description des normes
-
- Description de l'implémentation Linux
-
- Description historique
-
- STANDARDS
-
- NOTES
-
- Mises en garde
-
- Notes pour Linux
-
- Historique
-
- BOGUES
-
- VOIR AUSSI
-
- TRADUCTION
-
This document was created by
man2html,
using the manual pages.
Time: 15:52:10 GMT, May 22, 2024