wait
Section: System Calls (2)
Updated: 5 février 2023
Index
Return to Main Contents
NOM
wait, waitpid, waitid - Attendre la fin d'un processus
BIBLIOTHÈQUE
Bibliothèque C standard (libc, -lc)
SYNOPSIS
#include <sys/wait.h>
pid_t wait(int *_Nullable wstatus);
pid_t waitpid(pid_t pid, int *_Nullable wstatus, int options);
int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);
/* Il s'agit de l'interface de glibc et POSIX ; consultez les
NOTES pour des informations sur les appels système bruts. */
Exigences de macros de test de fonctionnalités pour la glibc (consulter
feature_test_macros(7)) :
waitid() :
Depuis la glibc 2.26 :
_XOPEN_SOURCE >= 500 || _POSIX_C_SOURCE >= 200809L
Pour la glibc antérieure et égale à 2.25 :
_XOPEN_SOURCE
|| /* Depuis la glibc 2.12: */ _POSIX_C_SOURCE >= 200809L
|| /* glibc <= 2.19: */ _BSD_SOURCE
DESCRIPTION
Tous ces appels système attendent qu'un des enfants du processus appelant
change d'état et permettent d'obtenir des informations sur l'enfant en
question. Un processus est considéré comme changeant d'état s'il termine,
s'il est stoppé par un signal ou s'il est relancé par un signal. Dans le cas
d'un enfant qui se termine, l'attendre permet au système de libérer les
ressources qui lui étaient allouées ; si le processus n'est pas attendu, il
reste en état de « zombie » (voir les NOTES plus bas).
Si un enfant a déjà changé d'état, ces appels système retournent
immédiatement. Sinon, ils bloquent jusqu'à ce qu'un enfant change d'état ou
qu'un gestionnaire de signal interrompe l'appel (sauf si les appels système
sont relancés automatiquement par l'option SA_RESTART de
sigaction(2)). Dans la suite de cette page, un enfant qui a changé d'état
et qui n'a pas été attendu est appelé prêt (waitable).
wait() et waitpid()
L'appel système wait() suspend l'exécution du processus appelant jusqu'à
ce que l'un de ses enfants se termine. L'appel wait(&status) est
équivalent à :
waitpid(-1, &wstatus, 0);
L'appel système waitpid() suspend l'exécution du processus appelant
jusqu'à ce qu'un enfant spécifié par l'argument pid change d'état. Par
défaut, waitpid() n'attend que les enfants terminés, mais ce comportement
peut être modifié par l'argument options, de la façon décrite ci-dessous.
La valeur de pid peut être l'une des suivantes :
- < -1
-
Attendre la fin de n'importe quel processus enfant appartenant au groupe de
processus d'ID -pid.
- -1
-
Attendre n'importe lequel des processus enfant.
- 0
-
Attendre la fin de n'importe quel processus enfant dont l'identifiant de
groupe du processus est égal à celui du processus appelant au moment de
l'appel à waitpid().
- > 0
-
Attendre la fin d'un enfant dont l'identifiant du processus est égal à la
valeur du processus numéro pid.
La valeur de l'argument option options est un OU binaire entre zéro ou
plus des constantes suivantes :
- WNOHANG
-
Ne pas bloquer si aucun enfant ne s'est terminé.
- WUNTRACED
-
Recevoir l'information concernant également les enfants bloqués (mais non
suivis par ptrace(2)). L'état des enfants suivis qui se sont terminés est
fourni même sans cette option.
- WCONTINUED (Depuis Linux 2.6.10)
-
Renvoyer également si un processus enfant stoppé a été relancé par le signal
SIGCONT.
(Pour les options spécifiques à Linux, voir plus bas.)
Si wstatus n'est pas NULL, wait() et waitpid() stockent l'état de
l'enfant dans la variable de type int pointée. Cet entier peut être
évalué avec les macros suivantes (qui prennent l'entier lui-même comme
argument, et pas un pointeur vers celui-ci, comme le font wait() et
waitpid() !) :
- WIFEXITED(wstatus)
-
Vrai si l'enfant s'est terminé normalement, c'est-à-dire par un appel à
exit(3) ou _exit(2) ou par un return depuis main().
- WEXITSTATUS(wstatus)
-
Donne le code de retour, consistant en les 8 bits de poids faible du
paramètre status fourni à exit(3) ou _exit(2) ou dans le return
de la routine main(). Cette macro ne peut être évaluée que si WIFEXITED a
renvoyé vrai.
- WIFSIGNALED(wstatus)
-
Vrai si l'enfant s'est terminé à cause d'un signal.
- WTERMSIG(wstatus)
-
Donne le numéro du signal qui a causé la fin de l'enfant. Cette macro ne
peut être évaluée que si WIFSIGNALED a renvoyé vrai.
- WCOREDUMP(wstatus)
-
Vrai si le processus enfant a produit une image mémoire (« core dump »)
(voir core(5)). Cette macro ne doit être évaluée que si WIFSIGNALED a
renvoyé vrai.
-
Cette macro n'est pas décrite par POSIX.1-2001 et n'est pas disponible sur
certaines implémentations d'UNIX (par exemple AIX ou SunOS). N'utilisez
cette macro qu'entourée de #ifdef WCOREDUMP ... #endif.
- WIFSTOPPED(wstatus)
-
Vrai si le processus enfant a été arrêté par l'envoi d'un signal. Cela n'est
possible que si l'on a effectué l'appel avec l'option WUNTRACED ou si
l'enfant est suivi (voir ptrace(2)).
- WSTOPSIG(wstatus)
-
Donne le numéro du signal qui a causé l'arrêt de l'enfant. Cette macro ne
peut être évaluée que si WIFSTOPPED renvoie vrai.
- WIFCONTINUED(wstatus)
-
(Depuis Linux 2.6.10) Vrai si le processus enfant a été relancé par
SIGCONT.
waitid()
L'appel système waitid(), disponible depuis Linux 2.6.9, fournit des
moyens plus fins de contrôler quels changements d'états attendre.
Les arguments idtype et id sélectionnent le(s) enfant(s) à attendre,
comme suit :
- idtype == P_PID
-
Attendre la fin de l'enfant dont l'identifiant du processus correspond à
id.
- idtype == P_PIDFD (depuis Linux 5.4)
-
Attendre la fin de l'enfant auquel fait référence le descripteur de fichier
PID spécifié dans id (voir pidfd_open(2) pour plus d'informations à
propos des descripteurs de fichier PID).
- idtype == P_PGID
-
Attendre la fin de l'enfant dont l'identifiant de groupe du processus
correspond à id. depuis Linux 5.4, si id vaut zéro, attendre pour
n'importe quel enfant qui est dans le même groupe de processus que le groupe
de processus de l'appelant au moment de l'appel.
- idtype == P_ALL
-
Attendre n'importe quel enfant ; l'argument id est ignoré.
Les changements d'état à attendre sont indiqués par un OU binaire des
attributs suivants dans le paramètre options :
- WEXITED
-
Attendre les enfants qui se sont terminés.
- WSTOPPED
-
Attendre les enfants qui ont été arrêtés par un signal.
- WCONTINUED
-
Attendre les enfants précédemment arrêtés qui ont été relancés par le signal
SIGCONT.
Les attributs suivants peuvent également être utilisés dans options :
- WNOHANG
-
Comme pour waitpid().
- WNOWAIT
-
Laisser l'enfant dans un état prêt ; un appel ultérieur à wait() pourra de
nouveau fournir des informations sur l'état de l'enfant.
Si l'appel réussit, waitid() remplit les champs suivants de la structure
siginfo_t pointée par infop :
- si_pid
-
L'identifiant de processus de l'enfant.
- si_uid
-
L'UID réel de l'enfant. Ce champ n'est pas rempli par la plupart des autres
implémentations.
- si_signo
-
Toujours SIGCHLD.
- si_status
-
Soit le code de retour de l'enfant donné à _exit(2) ou exit(3), soit
le signal ayant provoqué la terminaison, l'arrêt ou la relance de
l'enfant. Le champ si_code permet de savoir comment interpréter ce champ.
- si_code
-
L'un de CLD_EXITED (l'enfant a appelé _exit(2)), CLD_KILLED
(l'enfant a été tué par un signal), CLD_DUMPED (l'enfant a été tué par un
signal et a produit une image mémoire (core dump)), CLD_STOPPED (l'enfant
a été arrêté par un signal), CLD_TRAPPED (l'enfant suivi a été capturé)
ou CLD_CONTINUED (l'enfant a été relancé par SIGCONT).
Si WNOHANG est utilisé dans options et si aucun enfant n'est prêt,
waitid() renvoie 0 immédiatement et l'état de la structure
siginfo_t pointée par infop dépend de l'implémentation. Pour
différencier (de façon portable) ce cas de celui où un des enfants était
prêt, définissez à zéro le champ si_pid avant l'appel, et vérifiez que sa
valeur est différente de zéro après le renvoi de l'appel.
Le premier rectificatif technique POSIX.1-2008 (2013) ajoute l'exigence que
quand WNOHANG est spécifié dans options et si aucun enfant n'est prêt,
waitid() doit définir à zéro les champs si_pid et si_signo de la
structure. Dans Linux et d'autres implémentations qui respectent cette
exigence, il n'est pas nécessaire de définir à zéro le champ si_pid avant
l'appel à waitid(). Néanmoins, toutes les implémentations ne suivent pas
la spécification de POSIX.1 sur ce point.
VALEUR RENVOYÉE
wait() : en cas de réussite, l'identifiant du processus enfant terminé
est renvoyé ; en cas d'échec, la valeur de retour est -1.
waitpid() : s'il réussit, l'appel renvoie l'identifiant du processus
enfant dont l'état a changé ; si WNOHANG est utilisé et si un enfant (ou
plus) spécifié par pid existe, mais n'a pas encore changé d'état, la
valeur renvoyée est 0. En cas d'échec, -1 est renvoyé.
waitid() : renvoie 0 s'il réussit ou si WNOHANG est utilisé et
siaucun enfant spécifié dans id n'a encore changé d'état. En cas d'échec,
renvoie -1.
En cas d'échec, chacun de ces appels définit errno pour préciser
l'erreur.
ERREURS
- EAGAIN
-
Le descripteur de fichier PID spécifié dans id n'est pas bloquant et le
processus auquel il fait référence ne s'est pas terminé.
- ECHILD
-
(pour wait()) Le processus appelant n'a pas d'enfants qui n'ont pas été
attendus.
- ECHILD
-
(pour waitpid() ou waitid()) Le processus indiqué par pid
(waitpid()) ou idtype et id (waitid()) n'existe pas ou n'est pas
un enfant du processus appelant. (Cela peut arriver pour son propre enfant
si l'action de SIGCHLD est définie à SIG_IGN ; voir également le
passage de la section Notes sur Linux concernant les threads.)
- EINTR
-
WNOHANG n'est pas indiqué et un signal à intercepter ou SIGCHLD a été
reçu ; consultez signal(7).
- EINVAL
-
L'argument options n'est pas valable.
- ESRCH
-
(pour wait() ou waitpid()) pid est équivalent à INT_MIN.
STANDARDS
SVr4, 4.3BSD, POSIX.1-2001.
NOTES
Un enfant qui se termine mais n'a pas été attendu devient un « zombie ». Le noyau conserve des informations minimales sur le processus zombie
(identifiant, code de retour, informations d'utilisation des ressources)
pour permettre au parent de l'attendre plus tard et d'obtenir des
informations sur l'enfant. Tant que le zombie n'est pas effacé du système
par une attente, il prendra un emplacement dans la table des processus du
noyau, et si cette table est remplie, il sera impossible de créer de
nouveaux processus. Si un processus parent se termine, ses enfants zombies
(s'il y en a) sont adoptés par init(1) (ou par le processus suppresseur
(subreaper) le plus proche tel que défini par l'utilisation de
l'opération PR_SET_CHILD_SUBREAPER de prctl(2)) ; init(1) les
attend automatiquement pour supprimer les zombies.
POSIX.1-2001 indique que si l'action pour SIGCHLD est définie à
SIG_IGN ou si l'attribut SA_NOCLDWAIT est indiqué pour SIGCHLD
(voir sigaction(2)), les enfants qui se terminent ne deviennent pas des
zombies et un appel à wait() ou waitpid() sera bloquant jusqu'à ce que
tous les enfants soient terminés, et échouera ensuite en positionnant
errno à ECHILD. (La norme POSIX originale ne décrivait pas le
comportement si l'action pour SIGCHLD était SIG_IGN. Veuillez noter
que même si la disposition par défaut de SIGCHLD est « ignore », la
configuration explicite de la disposition de SIG_IGN entraîne un
traitement différent des processus enfants zombies.)
Linux 2.6 est conforme aux préconisations de POSIX. Cependant, Linux 2.4 et
les versions antérieures ne l'étaient pas. Lorsqu'un appel wait() ou
waitpid() était exécuté en ignorant SIGCHLD, les appels se
comportaient comme si SIGCHLD était pris en compte, c'est à dire que
l'appel restait bloqué en attendant que l'enfant suivant se termine, puis
renvoyait l'identifiant de processus et l'état de cet enfant.
Notes pour Linux
Dans le noyau Linux, un thread ordonnancé par le noyau n'est pas différent
d'un simple processus. En fait, un thread est juste un processus qui est
créé à l'aide de la routine --- spécifique à Linux --- clone(2). Les
routines portables, comme pthread_create(3), sont implémentées en
appelant clone(2). Avant Linux 2.4, un thread était simplement un cas
particulier de processus, et en conséquence un thread ne pouvait pas
attendre les enfants d'un autre thread, même si ce dernier appartenait au
même groupe de threads. Toutefois, POSIX réclame une telle fonctionnalité,
et depuis Linux 2.4 un thread peut, par défaut, attendre les enfants des
autres threads du même groupe.
Les options suivantes sont spécifiques à Linux et servent pour les
enfants créés avec clone(2) ; elles peuvent aussi, depuis Linux 4.7,
être utilisées avec waitid() :
- __WCLONE
-
Attendre uniquement des enfants clones. Sinon, attendre uniquement les
enfants non-clones (un enfant « clone » est un enfant qui n'envoie pas de
signal ou un autre signal que SIGCHLD à son père à sa terminaison). Cette
option est ignorée si __WALL est aussi indiqué.
- __WALL (depuis Linux 2.4)
-
Attendre tous les enfants, quel que soit leur type (clone ou non-clone).
- __WNOTHREAD (Depuis Linux 2.4)
-
Ne pas attendre les enfants des autres threads du même groupe de
threads. Cela était le cas par défaut avant Linux 2.4.
Depuis Linux 4.7, l'attribut __WALL est automatiquement impliqué si
l'enfant est suivi.
différences entre bibliothèque C et noyau
wait() est en fait une fonction de bibliothèque implémentée (dans glibc)
en tant qu'appel système à wait4().
sur certaines architectures, il n'y a pas d'appel système waitpid() ; à
la place, cette interface est implémentée au moyen d'une fonction
d'enveloppe de la bibliothèque C qui appelle wait4(2).
L'appel système brut waitid() prend un cinquième paramètre, de type
struct rusage *. Si ce paramètre n'est pas NULL, il est utilisé pour
renvoyer les informations d'utilisation des ressources au sujet du thread
enfant, de la même façon que wait4(2). Consultez getrusage(2) pour
plus de détails.
BOGUES
Selon la norme POSIX.1-2008, une application appelant waitid() doit
garantir que infop pointe sur une structure siginfo_t (c'est-à-dire
qu'elle ne pointe pas sur NULL). Sur Linux, si infop est NULL,
waitid() réussit, et renvoie l'identificateur du processus enfant
attendu. Dans la mesure du possible, les applications doivent éviter d'avoir
recours à cette fonctionnalité incohérente, non standard et superflue.
EXEMPLES
Le programme suivant montre l'utilisation de fork(2) et de
waitpid(). Le programme crée un processus enfant. Si aucun argument n'est
fourni dans la ligne de commande du programme, l'enfant suspend son
exécution avec pause(2), pour que l'utilisateur puisse lui envoyer des
signaux. Sinon, l'enfant se termine immédiatement en utilisant l'entier
fourni sur la ligne de commande comme code de retour. Le processus père
boucle en surveillant l'état de l'enfant avec waitpid() et utilise les
macros W*() décrites ci-dessus pour analyser le code d'état de l'enfant.
La session interactive suivante montre l'utilisation de ce programme :
$ ./a.out &
Le PID de l'enfant est 32360
[1] 32359
$ kill -STOP 32360
arrêté par le signal 19
$ kill -CONT 32360
relancé
$ kill -TERM 32360
tué par le signal 15
[1]+ Done ./a.out
$
Source du programme
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
int
main(int argc, char *argv[])
{
int wstatus;
pid_t cpid, w;
cpid = fork();
if (cpid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (cpid == 0) { /* Code exécuté par l'enfant */
printf("Le PID de l'enfant est %jd\n", (intmax_t) getpid());
if (argc == 1)
pause(); /* Attendre un signal */
_exit(atoi(argv[1]));
} else { /* Code exécuté par le parant */
do {
w = waitpid(cpid, &wstatus, WUNTRACED | WCONTINUED);
if (w == -1) {
perror("waitpid");
exit(EXIT_FAILURE);
}
if (WIFEXITED(wstatus)) {
printf("terminé, code=%d\n", WEXITSTATUS(wstatus));
} else if (WIFSIGNALED(wstatus)) {
printf("tué par le signal %d\n", WTERMSIG(wstatus));
} else if (WIFSTOPPED(status)) {
printf("arrêté par le signal %d\en", WSTOPSIG(wstatus));
} else if (WIFCONTINUED(wstatus)) {
printf("relancé\n");
}
} while (!WIFEXITED(wstatus) && !WIFSIGNALED(wstatus));
exit(EXIT_SUCCESS);
}
}
VOIR AUSSI
_exit(2), clone(2), fork(2), kill(2), ptrace(2),
sigaction(2), signal(2), wait4(2), pthread_create(3),
core(5), credentials(7), signal(7)
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>,
Cédric Boutillier <cedric.boutillier@gmail.com>,
Frédéric Hantrais <fhantrais@gmail.com>
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
-
- wait() et waitpid()
-
- waitid()
-
- VALEUR RENVOYÉE
-
- ERREURS
-
- STANDARDS
-
- NOTES
-
- Notes pour Linux
-
- différences entre bibliothèque C et noyau
-
- BOGUES
-
- EXEMPLES
-
- Source du programme
-
- VOIR AUSSI
-
- TRADUCTION
-
This document was created by
man2html,
using the manual pages.
Time: 08:06:38 GMT, May 18, 2024