WAIT(2)

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);

Exigences de macros de test de fonctionnalités pour la glibc (voir feature_test_macros(7)) :

waitid() : _SVID_SOURCE || _XOPEN_SOURCE

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 (supposant que les appels système ne sont pas automatiquement relancés en utilisant 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 appelant jusqu'à ce que l'un de ses fils se termine. L'appel wait(&status) est équivalent à :
    waitpid(-1, &status, 0);
L'appel système waitpid() suspend l'exécution du processus appelant jusqu'à ce que le fils spécifié par son pid ait changé d'état. Par défaut, waitpid() n'attend que les fils terminés, mais ce comportement est modifiable avec l'argument options comme décrit plus loin. La valeur de pid peut être l'une des suivantes :

< -1
    attendre la fin de n'importe lequel des processus fils dont le GID du processus est égal à la valeur absolue de pid.

-1  attendre n'importe lequel des processus fils.

0   attendre n'importe lequel des processus fils dont le GID du processus est égal à celui du processus appelant.

> 0 attendre n'importe lequel des processus fils dont le PID est égal à pid.

La valeur de options est un OU binaire entre 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.)

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. Cette macro ne peut ê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 (par exemple AIX, 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 la fin de n'importe quel fils appartenant au groupe de processus dont le GID est id.

idtype == P_ALL
    Attendre n'importe quel fils ; id est ignoré.

Les changements d'état du fils à attendre sont indiqué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 ultérieur à wait() pourra être utilisé pour récupérer l'information d'état du fils.

S'il réussit, waitid() remplit les champs suivants de la structure siginfo_t pointée par infop :

si_pid
    Le PID du fils.

si_uid
    L'UID réel du fils. (Ce champ n'est pas configuré sur la plupart des implémentations.)

si_signo
    Toujours 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 ayant provoqué la fin, le blocage ou la continuation 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é indiqué dans options et qu'il n'y a aucun fils dans un état 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é ; si WNOHANG était spécifié et qu'aucun fils spécifié par pid n'a encore changé d'état, 0 est renvoyé. En cas d'échec -1 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 ; voir signal(7).

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, informations 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 de nouveaux 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é. 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 fils zombies.) Linux 2.6 est conforme à cette spécification. Toutefois, Linux 2.4 (et antérieurs) ne le sont pas : si un appel à wait() ou waitpid() est effectué alors SIGCHLD est ignoré, l'appel se comporte comme si SIG_IGN 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, 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. Ceci était le cas par défaut avant Linux 2.4.

EXEMPLE
Le programme suivant montre l'utilisation de fork(2) et waitpid(). 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 retour. Le processus père exécute une boucle qui surveille le fils avec waitpid(), et utilise les macros W*() décrites plus haut pour analyser la valeur d'état de l'attente (wait()). La session shell suivante montre l'utilisation de ce programme :
$ ./a.out &
Le PID du fils 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
$
#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("Le PID du fils est %ld\n", (long) getpid());
        if (argc == 1)
            pause();                  /* Attendre un signal */
        _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("terminé, code=%d\n", WEXITSTATUS(status));
            } else if (WIFSIGNALED(status)) {
                printf("tué par le signal %d\n", WTERMSIG(status));
            } else if (WIFSTOPPED(status)) {
                printf("arrêté par le signal %d\n", WSTOPSIG(status));
            } else if (WIFCONTINUED(status)) {
                printf("relancé\n");
            }
        } while (!WIFEXITED(status) && !WIFSIGNALED(status));
        exit(EXIT_SUCCESS);
    }
}

VOIR AUSSI
clone(2), _exit(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 17 juillet 2008.

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.