waitpid(2)
Appel système
Attend la fin d'un processus enfant et récupère son statut : code de sortie ou signal qui l'a tué. Sans cet appel, l'enfant terminé reste zombie.
#include <sys/wait.h>
pid_t waitpid(pid_t pid, int *wstatus, int options);Description
waitpid suspend le processus appelant jusqu'à ce qu'un de ses enfants change d'état, en pratique jusqu'à ce qu'il se termine. Il libère alors ce qui restait de l'enfant dans le noyau : un enfant terminé qu'on n'a pas encore attendu est un zombie.
Le paramètre pid choisit qui attendre : un PID positif vise cet enfant précis, -1 accepte n'importe quel enfant. wait(&status) est exactement waitpid(-1, &status, 0). Le dernier paramètre accepte des options, la plus utile étant WNOHANG, qui rend la main tout de suite si aucun enfant n'a fini.
Si wstatus n'est pas NULL, waitpid y range un entier codé qu'on lit avec ces macros :
| Macro | Signification |
|---|---|
WIFEXITED(s) | vrai si l'enfant a fini normalement (exit, return dans main) |
WEXITSTATUS(s) | son code de sortie, les 8 bits de poids faible de la valeur passée à exit |
WIFSIGNALED(s) | vrai si un signal a tué l'enfant |
WTERMSIG(s) | le numéro de ce signal |
Valeur de retour
Le PID de l'enfant dont l'état a changé. Avec WNOHANG, 0 si les enfants visés existent mais n'ont pas encore changé d'état. En cas d'erreur, -1 et errno : ECHILD quand il n'y a aucun enfant à attendre, EINTR quand un signal a interrompu l'attente.
Pièges
WEXITSTATUSn'a de sens que siWIFEXITEDest vrai, etWTERMSIGque siWIFSIGNALEDest vrai. Teste toujours la première macro.Le code de sortie est tronqué à 8 bits :
exit(256)se lit comme 0,exit(-1)comme 255.Un enfant ne s'attend qu'une fois. Un second
waitpidsur le même PID échoue avecECHILD.
Exemple
#include <stdio.h>#include <stdlib.h>#include <sys/wait.h>#include <unistd.h>
static void rapport(pid_t pid){ int status;
if (waitpid(pid, &status, 0) == -1) { perror("waitpid"); return; } if (WIFEXITED(status)) printf("%d : terminé, code %d\n", pid, WEXITSTATUS(status)); else if (WIFSIGNALED(status)) printf("%d : tué par le signal %d\n", pid, WTERMSIG(status));}
int main(void){ pid_t a = fork(); if (a == 0) exit(256);
pid_t b = fork(); if (b == 0) abort();
rapport(a); rapport(b); rapport(b); return 0;}$ gcc -Wall -Wextra statut.c -o statut$ ./statut35 : terminé, code 036 : tué par le signal 6waitpid: No child processesLe premier enfant a demandé 256 et le parent lit 0. Le second est tué par SIGABRT, le signal 6 que déclenche abort. Le troisième appel vise un enfant déjà attendu, d'où ECHILD.
signal_watchdog
Écris signal_watchdog, qui lance une fonction dans un enfant, lit dans son statut comment il a fini et ne laisse aucun zombie, même si le délai expire.