fork - Créer un processus enfant
Bibliothèque C standard (
libc,
-lc)
#include <unistd.h>
pid_t fork(void);
fork() crée un nouveau processus en copiant le processus appelant.
Le nouveau processus est appelé
enfant
(« child »). Le processus appelant est
appelé
parent.
Les processus parent et enfant fonctionnent dans des espaces mémoire
séparés. Au moment du
fork(), les deux espaces
mémoire ont le même contenu. Les écritures en
mémoire, les associations de fichier (
mmap(2)) et les
désassociations (
munmap(2)) effectuées par un processus
ne concernent pas l'autre.
Le processus enfant est une copie exacte du processus parent, sauf sur les
points suivants :
- •
- L'enfant a son propre identifiant de processus unique et ce
PID ne correspond à l'identifiant d'aucune session ou d'aucun
groupe de processus existant ( setpgid(2)).
- •
- L'identifiant de processus parent (PPID) de l'enfant est
l'identifiant de processus (PID) du parent.
- •
- L'enfant n'hérite pas des verrouillages
mémoire du parent ( mlock(2), mlockall(2)).
- •
- Les utilisations de ressources (getrusage(2)) et les
compteurs de temps processeur ( times(2)) sont remis à
zéro dans l'enfant.
- •
- L'ensemble de signaux en attente dans l'enfant est
initialement vide ( sigpending(2)).
- •
- L'enfant n'hérite pas des opérations sur les
sémaphores de son parent ( semop(2)).
- •
- L'enfant n'hérite pas des verrouillages
d’enregistrements associés au processus de son parent (
fcntl(2)) (en revanche, il hérite des verrouillages de
description de fichier ouvert fcntl(2) et des verrouillages
flock(2) de son parent).
- •
- L'enfant n'hérite pas des temporisations de son
parent ( setitimer(2), alarm(2),
timer_create(2)).
- •
- L'enfant n'hérite pas des opérations d'E/S
asynchrones en cours de son parent ( aio_read(3),
aio_write(3)) et n'hérite d'aucun contexte d'E/S asynchrone
de son parent (consultez io_setup(2)).
Les attributs de processus de la liste précédente sont tous
définis dans POSIX.1. Les processus parent et enfant diffèrent
également par les propriétés spécifiques Linux
suivantes :
- •
- L'enfant n'hérite pas des notifications de
modification de répertoire (dnotify) de son parent (voir la
description de F_NOTIFY dans fcntl(2)).
- •
- Le drapeau PR_SET_PDEATHSIG de prctl(2) est
réinitialisé, de manière à ce que l'enfant ne
reçoive pas de signal lorsque son parent se termine.
- •
- La valeur de temporisation relâchée par
défaut est définie à la valeur de temporisation
relâchée actuelle de son parent. Veuillez consulter la
description de PR_SET_TIMERSLACK dans prctl(2).
- •
- Les projections en mémoire qui ont été
marquées avec l'attribut MADV_DONTFORK de madvise(2)
ne sont pas héritées lors d'un fork().
- •
- La mémoire dans les plages d'adresses ayant
été marquées par un attribut MADV_WIPEONFORK
de madvise(2) est remise à zéro dans l'enfant
après un fork() (le paramètre MADV_WIPEONFORK
reste en place pour ces plages d'adresses dans l'enfant).
- •
- Le signal de terminaison de l'enfant est toujours
SIGCHLD (consultez clone(2)).
- •
- Les bits de permission d'accès au port
indiqués par ioperm(2) ne sont pas hérités par
l'enfant ; l'enfant doit activer avec ioperm(2) les bits
dont il a besoin.
Notez également les points suivants :
- •
- Le processus enfant est créé avec un unique
thread — celui qui a appelé fork(). L'espace
d'adressage virtuel complet du parent est copié dans l'enfant, y
compris l'état des mutex, les variables de condition, et autres
objets de pthreads ; l'utilisation de pthread_atfork(3) peut
être utile pour traiter les problèmes que cela peut
occasionner.
- •
- Après un fork() dans un programme
multithreadé, l'enfant ne peut appeler en toute
sécurité que les fonctions async-signal-safe (voir
signal-safety(7)) jusqu'au moment où il appelle
execve(2).
- •
- L'enfant hérite de copies des descripteurs de
fichier ouverts du parent. Chaque descripteur de fichier de l'enfant
renvoie à la même description de fichier ouvert (consultez
open(2)) que le descripteur de fichier correspondant dans le
processus parent. Cela signifie que les deux descripteurs partagent les
attributs d'état du fichier, le décalage et les attributs
d'E/S liés aux signaux (voir la description de F_SETOWN et
F_SETSIG dans fcntl(2)).
- •
- L'enfant hérite de copies des descripteurs de
l'ensemble des files de messages ouvertes du parent (consultez
mq_overview(7)). Chaque descripteur de fichier de l'enfant renvoie
à la même description de file de messages ouverte que le
descripteur correspondant dans le parent. Cela signifie que les deux
descripteurs partagent leurs attributs ( mq_flags).
- •
- L'enfant hérite d'une copie de l'ensemble des flux
de répertoire ouverts par le parent (consultez opendir(3)).
POSIX.1 indique que les flux de répertoire correspondant dans le
parent et l'enfant peuvent partager le positionnement du flux de
répertoire ; sous Linux/glibc, ce n'est pas le cas.
En cas de succès, le PID de l'enfant est renvoyé au parent, et
0 est renvoyé à l'enfant. En cas d'échec
-1
est renvoyé au parent, aucun processus enfant n'est créé,
et
errno est positionné pour indiquer l'erreur.
- EAGAIN
- Une limite imposée par le système du nombre
de threads a été atteinte. Il existe un certain nombre de
limites qui peuvent occasionner cette erreur :
- •
- La limite de ressource souple RLIMIT_NPROC
(définie avec setrlimit(2)), qui limite le nombre de
processus et de threads pour l'ID d'un utilisateur réel, a
été atteinte ;
- •
- La limite du système du noyau du nombre de processus
et de threads, /"proc/sys/kernel/threads-max, a
été atteinte (voir proc(5)) ;
- •
- Le numéro maximal de PID,
/proc/sys/kernel/pid_max, a été atteint (voir
proc(5)) ;
- •
- Le nombre maximal de PID (pids.max) imposée
par le contrôleur de « nombre de
processus » cgroup (PID) a été atteinte.
- EAGAIN
- L’appelant parent opère sous la politique
d’ordonnancement SCHED_DEADLINE et n’a pas
l’attribut reset-on-fork activé. Consultez
sched(7).
- ENOMEM
-
fork() a échoué car le noyau n'a plus
assez de mémoire.
- ENOMEM
- Il y a eu une tentative de créer un processus enfant
dans l'espace de noms d'un PID dont le processus
« init » s'est terminé. Voir
pid_namespaces(7).
- ENOSYS
-
fork() n'est pas géré sur cette
plate-forme (par exemple sur du matériel sans unité de
gestion mémoire).
-
ERESTARTNOINTR (depuis Linux 2.6.17)
- L'appel système a été interrompu par
un signal et va être redémarré (cela n'est visible
qu'à l'occasion d'un trace()).
POSIX.1-2001, POSIX.1-2008, SVr4, 4.3BSD.
Sous Linux,
fork() est implémenté en utilisant une
méthode de copie à l'écriture. Cela consiste à ne
faire la véritable duplication d'une page mémoire que lorsqu'un
processus en modifie une instance. Tant qu'aucun des deux processus
n'écrit dans une page donnée, celle‐ci n'est pas vraiment
dupliquée. Ainsi les seules pénalisations induites par
fork() sont le temps et la mémoire nécessaires à
la copie de la table des pages du parent ainsi que la création d'une
structure unique de tâche pour l'enfant.
Depuis la glibc 2.3.3, plutôt que d'invoquer l'appel
système
fork() du noyau, l'enveloppe
fork() de la glibc
qui est fournie comme faisant partie de l'implémentation de threading
NPTL invoque
clone(2) avec des attributs qui fournissent le même
effet que l'appel système traditionnel (un appel à
fork()
est équivalent à un appel à
clone(2) avec
flags valant exactement
SIGCHLD). L'enveloppe de la glibc
invoque tous les gestionnaires de fourche
(« fork ») établis avec
pthread_atfork(3).
Consultez
pipe(2) et
wait(2) pour plus d'exemples.
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int
main(void)
{
pid_t pid;
if (signal(SIGCHLD, SIG_IGN) == SIG_ERR) {
perror(
exit(EXIT_FAILURE);
}
pid = fork();
switch (pid) {
case -1:
perror("fork");
exit(EXIT_FAILURE);
case 0:
puts("Child exiting.");
exit(EXIT_SUCCESS);
default:
printf("L'enfant est le PID %jd\n", (intmax_t) pid);
puts("Parent exiting.");
exit(EXIT_SUCCESS);
}
}
clone(2),
execve(2),
exit(2),
setrlimit(2),
unshare(2),
vfork(2),
wait(2),
daemon(3),
pthread_atfork(3),
capabilities(7),
credentials(7)
La traduction française de cette page de manuel a été
créée par Christophe Blaess
<
https://www.blaess.fr/christophe/>, Stéphan Rafin
<
[email protected]>, Thierry Vignaud
<
[email protected]>, François Micaux, Alain Portal
<
[email protected]>, Jean-Philippe Guérard
<
[email protected]>, Jean-Luc Coulon (f5ibh)
<
[email protected]>, Julien Cristau
<
[email protected]>, Thomas Huriaux <
[email protected]>,
Nicolas François <
[email protected]>, Florentin
Duneau <
[email protected]>, Simon Paillard
<
[email protected]>, Denis Barbier
<
[email protected]>, David Prévot <
[email protected]> et
Jean-Philippe MENGUAL <
[email protected]>
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 à
[email protected]