wait

Autres langues

Langue: fr

Version: 11 novembre 2004 (mandriva - 01/05/08)

Section: 2 (Appels système)

NOM

wait, waitid, waitpid - Attendre qu'un processus change d'état

SYNOPSIS

#include <sys/types.h>
#include <sys/wait.h>

pid_t wait(int *status);
pid_t waitpid(pid_t pid, int *status, int options);
int waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options);

DESCRIPTION

Tous ces appels système sont utilisés pour attendre le changement d'état du fils d'un processus appelant, et pour obtenir des informations sur le fils dont l'état a changé. Un changement d'état peut être: le fils est terminé ; le fils a été interrompu par un signal ; ou le fils a été relancé par un signal. Dans le cas de la fin d'un processus, la réalisation d'un wait() permet au système de libérer les ressources associées au fils ; si un wait() n'est pas effectué, le fils qui s'est terminé reste dans l'état de « zombie » (voir la section NOTES plus bas).

Si le fils a déjà changé d'état, ces appels reviennent immédiatement. Autrement, ils bloquent jusqu'à ce que soit un fils change d'état, soit un gestionnaire de signaux interrompe l'appel (suposant que les appels système ne sont pas automatiquement relancés en utilsant l'attribut SA_RESTART de sigaction(2)). Dans la suite de cette page, nous qualifierons d'attentiste (Ndt : waitable) un fils dont l'état a changé et qui n'a pas encore été attendu par l'un de ces appels système.

wait() et waitpid()

L'appel système wait() suspend l'exécution du processus courant jusqu'à ce que l'un de ses fils soit achevé. L'appel wait(&status) est équivalent à :
 
     waitpid(-1, &status, 0);
 

L'appel système waitpid() suspend l'exécution du processus courant jusqu'à ce que le fils spécifié par son pid ait changé d'état. Par défaut, waitpid() attend seulement la fin des fils mais ce comportement est modifiable avec l'argument options comme décrit plus loin.

La valeur de pid peut être :

< -1
signifiant d'attendre n'importe lequel des processus fils dont le GID du processus est égal à la valeur absolue de pid.
-1
signifiant d'attendre n'importe lequel des processus fils.
0
signifiant d'attendre n'importe lequel des processus fils dont le GID du processus est égal à celui du processus appelant.
> 0
signifiant d'attendre n'importe lequel des processus fils dont le PID est égal à pid.

La valeur de options est un OU de zéro ou plus des constantes suivantes :

WNOHANG
revenir immédiatement si aucun fils n'est achevé.
WUNTRACED
revenir si un fils est bloqué (mais non suivi par ptrace(2)). L'état des fils suivis est fourni même sans cette option. traced
WCONTINUED
(Depuis Linux 2.6.10) revenir si un fils bloqué a été relancé par la délivrance du signal SIGCONT.

(Pour les options spécifiques à Linux, voir plus bas).

Les options WUNTRACED et WCONTINUED ne sont effectives que si l'attribut SA_NOCLDSTOP n'a pas été spécifié pour le signal SIGCHLD (voir sigaction(2)).

Si status n'est pas NULL, wait() et waitpid() enregistre les informations sur l'état dans l'entier int sur lequel il pointe. cet entier est analysé avec les macros suivantes (qui prennent en argument l'entier lui-même, pas un pointeur sur lui, comme cela est fait dans wait() et waitpid()!) :

WIFEXITED(status)
renvoie vrai si le fils s'est terminé normalement, c'est-à-dire par un appel à exit(3) ou _exit(2), ou bien par un retour de main().
WEXITSTATUS(status)
renvoie le code de sortie du fils. Ce code est constitué par les 8 bits de poids faibles de l'argument status que le fils a fourni à exit(3) ou à _exit(2) ou l'argument d'une commande de retour dans main(). Cette macro ne peut être évaluée que si WIFEXITED a renvoyé vrai.
WIFSIGNALED(status)
renvoie vrai si le fils s'est terminé à cause d'un signal.
WTERMSIG(status)
renvoie le numéro du signal qui a causé la fin du fils. Cette macro ne peut être évaluée que si WIFSIGNALED a renvoyé vrai.
WCOREDUMP(status)
renvoie vrai si le fils a créé un fichier core. returns true if the child produced a core dump.. Cette macro ne peut être évaluée que si WIFSIGNALED a renvoyé vrai. Cette macro n'est pas spécifiée dans POSIX.1-2001 et n'est pas disponible sur certaines implémentations (par exemple AIS, SunOS). N'utilisez ceci qu'encadré par #ifdef WCOREDUMP ... #endif.
WIFSTOPPED(status)
renvoie vrai si le fils a été arrêté par la délivrance d'un signal. Cette macro n'a de sens que si l'on a effectué l'appel avec l'option WUNTRACED ou lorsque l'appel est en cours de suivi (voir ptrace(2)).
WSTOPSIG(status)
renvoie le numéro du signal qui a causé l'arrêt du fils. Cette macro ne peut être évaluée que si WIFSTOPPED renvoie vrai.
WIFCONTINUED(status)
(Depuis Linux 2.6.10) renvoie vrai si le processus fils a été relancé par la délivrance du signal SIGCONT.

waitid()

L'appel système waitid() (disponible depuis Linux 2.6.9) fournit un contrôle plus précis sur les changements d'états des fils que l'on attend.

Les arguments idtype et id sélectionnent, de la manière suivante, le(s) fils à attendre :

idtype == P_PID
Attendre le fils dont le PID est id.
idtype == P_PGID
Attendre tous les fils dont le GID du processus est id.
idtype == P_ALL
Attendre tous les fils ; id est ignoré.

Les changement d'état du fils à attendre sont spécifiés par un OU entre un ou plusieurs des attributs d'options suivants :

WEXITED
Attendre les fils qui se sont terminés.
WSTOPPED
Attendre les fils qui ont été bloqués par la délivrance d'un signal.
WCONTINUED
Attendre les fils, précédemment bloqués, qui ont été relancés par la délivrance d'un signal SIGCONT.

Les attributs suivants peuvent également être utilisés dans options :

WNOHANG
Comme pour waitpid().
WNOWAIT
Laisser le fils dans un état attentiste : un appel ulérieur à wait pourra être utilisé pour récupérer l'information d'état du fils.

En cas de succès, waitid() remplit les champs suivants de la structure siginfo_t pointée par infop :

si_pid
Le PID du fils.
si_uid
L'UID reél du fils. (Ce champ n'est pas configuré sur la plupart des implémentations.)
si_signo
Toujous remplit avec SIGCHLD.
si_status
Soit le code de retour du fils, tel qu'il a été fourni à _exit(2) (ou à exit(3)), soit le signal qui a provoqué la fin, le blocage ou la continuaison du fils. Le champ si_code peut être utilisé pour savoir comment interpréter ce champ.
si_code
Remplit avec l'une des valeurs suivantes : CLD_EXITED (le fils a appelé _exit(2)) ; CLD_KILLED (le fils a été tué par un signal) ; CLD_STOPPED (le fils a été bloqué par un signal) ; ou CLD_CONTINUED (le fils a été relancé par SIGCONT).

Si WNOHANG a été spécifié dans options et qu'il n'y a aucun fils dans un étét attentiste, waitid() renvoie immédiatement 0 et l'état de la structure siginfo_t pointée par infop est indéterminée. Pour différencier ce cas où un fils était dans un état attentiste, remplissez avec zéro le champ si_pid avant l'appel et vérifier s'il y a une valeur non nulle dans ce champ après le retour de l'appel.

VALEUR RENVOYÉE

wait() : En cas de réussite, le PID du fils qui s'est terminé est renvoyé, en cas d'échec -1 est renvoyé.

waitpid() : En cas de réussite, le PID du fils dont l'état a changé est renvoyé, en cas d'échec -1 est renvoyé ; si WNOHANG était spécifié et qu'aucun fils spécifié par pid n'a encore changé d'état, 0 est renvoyé.

waitid() : renvoie 0 s'il réussit ou si WNOHANG était spécifié et qu'aucun fils spécifié par id n'a encore changé d'état ; en cas d'échec -1 est renvoyé.

Chacun de ces appels remplissent errno avec une valeur appropriée dans le cas d'une erreur.

ERREURS

ECHILD (pour wait())
Le processus appelant n'a aucun fils à attendre.
ECHILD (pour waitpid() ou waitid())
Le processus indiqué par pid (waitpid()) ou idtype et id (waitid()) n'existe pas, ou n'est pas un fils du processus appelant. (Ceci peut arriver pour son propre fils si l'action de SIGCHLD est placée sur SIG_IGN, voir également le passage de la section Notes Linux concernant les threads).
EINTR
WNOHANG n'est pas indiqué, et un signal à intercepter ou SIGCHLD a été reçu.
EINVAL
L'argument options est invalide.

CONFORMITÉ

SVr4, BSD 4.3, POSIX.1-2001.

NOTES

Un fils qui se termine et qui n'était pas attendu devient un « zombie ». Le noyau conserve un ensemble minimal d'informations sur le processus zombie (PID, état de fin, information d'utilisation des ressources) pour permettre au père d'effectuer plus tard un wait() pour obtenir les informations sur le fils.

Aussi longtemps qu'un zombie n'est pas supprimé du système par un wait(), il utilisera un emplacement dans la table des processus du noyau et si la table est pleine, il ne sera plus possible de créer d'autres processus. Si un processus père se termine, ses fils « zombie », s'il en existe, seront adopté par init(8), qui effectuera automatiquement un wait() pour supprimer les zombies.

POSIX.1-2001 indique que si la disposition de SIGCHLD est configurée à SIG_IGN ou que l'attribut SA_NOCLDWAIT est configuré pour SIGCHLD (voir sigaction(2)), les fils qui se terminent ne deviennent pas des zombies et un appel à wait() ou waitpid() bloquera jusqu'à ce que tous les fils se terminent, puis échouera et écrira ECHILD dans errno. (La norme POSIX originale laissait le comportement avec SIGCHLD à SIG_IGN indéterminé.) Linux 2.6 est conforme à cette spécification. Toutefois, Linux 2.4 (et précédent) ne le sont pas : si un appel à wait() ou waitpid() est effectué alors SIGCHLD est ignoré, l'appel se comporte comme si SIGCHLD n'était pas ignoré, c'est-à-dire qu'il bloquera jusqu'à la première fin d'un fils et renverra le PID et l'état du fils.

Notes 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 ne peuvent pas ê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, quelques soient leurs types (clone ou non-clone).
__WNOTHREAD
(Depuis Linux 2.4) Ne pas attendre les enfants des autres threads du même groupe de threads. Ceci était le cas par défaut avant Linux 2.4.

EXEMPLE

Le programme suivant montre l'utilisation de fork(2) et waitpid(2). le programme crée un processus fils. Si aucun argument n'est fourni sur la ligne de commande du programme, le fils suspend son exécution avec pause(2) pour permettre à l'utilisateur d'envoyer des signaux au fils. Autrement, s'il y un argument sur la ligne de commande, le fils s'achève immédiatement, utilisant l'entier fourni sur la ligne de commande comme code de sortie. Le processus père exécute une boucle qui surveille le fils avec waitpid(2), et utilise les macros W*() décrites plus haut pour analyser la valeur d'état de l'attente (wait(2)).

La session shell suivante montre l'utilisation de ce programme :

 
 $ ./a.out &
 Child PID is 32360
 [1] 32359
 $ kill -STOP 32360
 stopped by signal 19
 $ kill -CONT 32360
 continued
 $ kill -TERM 32360
 killed by signal 15
 [1]+  Done                    ./a.out
 $
 
 #include <sys/wait.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <stdio.h>
 
 int
 main(int argc, char *argv[])
 {
     pid_t cpid, w;
     int status;
 
     cpid = fork();
     if (cpid == -1) {
         perror("fork");
         exit(EXIT_FAILURE);
     }
 
     if (cpid == 0) {            /* Code exécuté par le fils */
         printf("Child PID is %ld\n", (long) getpid());
         if (argc == 1)
             pause();                    /* Wait for signals */
         _exit(atoi(argv[1]));
 
     } else {                    /* Code exécuté par le père */
         do {
             w = waitpid(cpid, &status, WUNTRACED | WCONTINUED);
             if (w == -1) {
                 perror("waitpid");
                 exit(EXIT_FAILURE);
             }
 
             if (WIFEXITED(status)) {
                 printf("exited, status=%d\n", WEXITSTATUS(status));
             } else if (WIFSIGNALED(status)) {
                 printf("killed by signal %d\n", WTERMSIG(status));
             } else if (WIFSTOPPED(status)) {
                 printf("stopped by signal %d\n", WSTOPSIG(status));
             } else if (WIFCONTINUED(status)) {
                 printf("continued\n");
             }
         } while (!WIFEXITED(status) && !WIFSIGNALED(status));
         exit(EXIT_SUCCESS);
     }
 }
 

VOIR AUSSI

_exit(2), clone(2), fork(2), kill(2), ptrace(2), sigaction(2), signal(2), wait4(2), pthread_create(3), credentials(7), signal(7)

TRADUCTION

Ce document est une traduction réalisée par Christophe Blaess <http://www.blaess.fr/christophe/> le 15 octobre 1996, mise à jour par Alain Portal <aportal AT univ-montp2 DOT fr> le 30 mai 2006 et révisée le 28 novembre 2007.

L'équipe de traduction a fait le maximum pour réaliser une adaptation française de qualité. La version anglaise la plus à jour de ce document est toujours consultable via la commande : « LANG=C man 2 wait ». N'hésitez pas à signaler à l'auteur ou au traducteur, selon le cas, toute erreur dans cette page de manuel.