Le signal SIGCHLD (anciennement SIGCLD) est un signal utilisé pour réveiller un processus
dont un des fils vient de mourir. C'est pourquoi il est traité
différemment des autres signaux. La réaction à la réception d'un
signal SIGCHLD est de repositionner le bit pendant à zéro, et d'ignorer
le signal, mais le processus a quand même été réveillé pour
cela. L'effet d'un signal SIGCHLD est donc uniquement de réveiller un
processus endormi en priorité interruptible.
Si le processus capture les signaux SIGCHLD, il invoque alors la procédure de
traitement définie par l'utilisateur comme il le fait pour les autres signaux,
ceci en plus du traitement par défaut.
Le traitement normal est lié à la primitive wait qui permet de
récupérer la valeur de retour (exit status) d'un processus fils. En
effet, la primitive wait est bloquante et c'est la réception du signal
qui va réveiller le processus, et permettre la fin de l'exécution de
la primitive wait.
Un des problèmes de la gestion de signaux System V est le fait que le signal
SIGCHLD est reçu (raised) au moment de la pose d'une fonction de traitement.
Ces propriétés du signal SIGCHLD peuvent induire un bon nombre d'erreurs.
Par exemple, dans le programme suivant nous positionnons une fonction de traitement dans laquelle nous repositionnons la fonction de traitement. Comme sous System V, le comportement par défaut est repositionné pendant le traitement d'un signal. Or le signal est levé à la pose de la fonction de traitement, d'où une explosion de la pile.
#include <stdio.h> #include <unistd.h> /* ancienne norme */ #include <signal.h> void hand(int sig) { signal(sig, hand); printf("message qui n'est pas affiche\n"); } main() { signal(SIGCHLD, hand); printf("ce printf n'est pas execute\n"); }Sur les HP, un message d'erreur vous informe que la pile est pleine : stack growth failure.
Deuxième exemple :
#include <signal.h> #include <sys/wait.h> int pid, status; void hand(int sig) { printf(" Entree dans le handler \n"); system("ps -l"); /* affichage avec etat zombi du fils */ if ((pid = wait(&status)) == -1) /* suppression du fils zombi */ { perror("wait handler "); return ; } printf(" wait handler pid: %d status %d \n", pid, status); return; } main() { signal(SIGCHLD,hand); /* installation du handler */ if (fork() == 0) { /* dans le fils */ sleep(5); exit(2); } /* dans le pere */ if ((pid = wait(&status)) == -1) /* attente de terminaison du fils */ { perror("wait main "); return ; } printf(" wait main pid: %d status %d \n", pid, status); }résultat:
Entree dans le handler F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME COMD 1 S 121 6792 6667 0 158 20 81ac180 6 49f5fc ttys1 0:00 sigchld 1 S 121 6667 6666 0 168 20 81ac700 128 7ffe6000 ttys1 0:00 tcsh 1 Z 121 6793 6792 0 178 20 81bda80 0 ttys1 0:00 sigchld 1 S 121 6794 6792 0 158 20 81ac140 78 4a4774 ttys1 0:00 sh 1 R 121 6795 6794 4 179 20 81bd000 43 ttys1 0:00 ps wait handler pid: 6793 status 512 (2 * 256) wait main: Interrupted system callA la mort du fils, Le père reçoit le signal SIGCHLD (alors qu'il était dans le wait du main), puis le handler est executé, et ps affiche bien le fils zombi. Ensuite c'est le wait du handler qui prend en compte la terminaison du fils. Au retour du handler, l'appel a wait du main retourne -1, puisqu'il avait été interrompu par SIGCHLD.
Next: Manipulation de la pile Up: Problèmes de la gestion Previous: Problèmes de la gestion
Dominique REVUZ