chapitre 17. Signaux - Département Informatique

Commentaires

Transcription

chapitre 17. Signaux - Département Informatique
UNSA
UFR Sciences
Université de Nice Sophia-Antipolis
Département Informatique
Licence d’informatique et Maîtrise EEA – Module L3I6
Cours Système
et
Réseaux
Roger Rousseau
CNRS-UNSA/I3S
Version 4.1
Janvier 2006
17. SIGNAUX
8.0
Sommaire
Chapitre 17
Communication par signaux
suite(1)
6) Signification des signaux
7) Autres primitives de signalements :
raise, abort
1) Communication synchrone vs asynchrone
8) Réveils avec horloge (timers) :
setitimer, getitimer, alarm...
2) Concept de signal
3) Traitement d’un signal
signal
4) Signalement explicite :
kill
9) Mise en attente d’un processus :
attente active, pause, sleep, nanosleep
5) Etats, description d’un signal
545
17. SIGNAUX
8.0
Sommaire
546
17. SIGNAUX
8.1 Communication synchrone vs asynchrone
Communication synchrone vs asynchrone
suite(2)
10) Primitives POSIX fiables :
sigaddset, sigaction, sigprocmask,
sigpending, sigsuspend
Deux mécanismes fondamentaux de communication
entre processus :
✱
synchrone, plus facile à programmer,
✱
asynchrone, plus délicate à programmer.
547
17. SIGNAUX
8.1 Communication synchrone vs asynchrone
548
17. SIGNAUX
Communication synchrone
8.1 Communication synchrone vs asynchrone
Communication synchrone :
IPC
suite(1)
C’est le processus qui décide du moment où il souhaite
communiquer, par un appel système.
Les IPC (Interprocess Communication) sont des mécanismes
de communication synchrone, plus faciles à utiliser.
Dans les systèmes U NIX on dispose des IPC :
=> type boîte à lettres
Cela peut conduire à une mise en attente si l’événement attendu ne s’est pas produit : (blocage plus ou moins long).
Remarque :
au niveau microscopique, il n’y a que des communications
synchrones : par exemple, une interruption au niveau du
cycle d’exécution des instructions machine.
549
✱
sans partage de mémoire,
dans une structure de type flot de caractères ou de
messages :
✱
avec partage de mémoire :
segment de mémoire partagée, sémaphores.
550
Communication
asynchrone(événementielle) avec signaux
IPC sans partage de mémoire
entre processus d’une même machine :
✱
• tube (volatile, uni- ou bi-directionnel),
Lorsque un événement arrive, le système force le processus à exécuter un code spécial : une routine, un traitant.
• FIFO (idem, mais persistants),
• file de messages, avec priorité (SVR4),
entre processus sur le réseau :
✱
Le déroutement se produit (s’il est autorisé par le processus)
à un moment arbitraire de l’exécution du processus.
• socket : divers protocoles, messages, (BSD)
Rappel: les “IPC système V” : file de messages, sémaphore,
segments de mémoire partagée.
=> type appel téléphonique
551
17. SIGNAUX
8.1 Communication synchrone vs asynchrone
Communication asynchrone
le noyau et le matériel :
✱
les processus et le noyau :
signal,
les différentes parties d’un programme :
✱
8.1 Communication synchrone vs asynchrone
Communication asynchrone
interruption,
l’utilisateur et un serveur graphique :
✱
17. SIGNAUX
suite(1)
Dans les systèmes, les communications asynchrones se retrouvent à plusieurs niveaux de dialogues entre :
✱
552
événement,
suite(2)
La programmation événementielle est très délicate et source
d’erreurs :
✱
mauvaise lisibilité des programmes (effet spaghetti),
✱
blocage, perte d’événements, conditions de vitesse,
✱
si ressources partagées, exclusion mutuelle nécessaire,
exception,
553
17. SIGNAUX
8.1 Communication synchrone vs asynchrone
554
17. SIGNAUX
8.1 Communication synchrone vs asynchrone
Sous-processus implicites
Raison des difficultés :
sous-processus implicites
suite(1)
Traitement d’un signal = scheduling implicite
Rappel sur le scheduling des processus explicites
signal s
signal s
Scheduler
Scheduler
P1
P1
P2
return
return
P3
traitant signal s
556
555
17. SIGNAUX
8.2 Concept de signal
17. SIGNAUX
Concept de signal
Liste alphabétique des signaux
Sous U NIX, un signal est un événement émis à un processus
ou à un groupe de processus bien identifiés qui :
✱
a nom (une constante entière) connu du système,
✱
a un traitant par défaut ou défini par une primitive système :
• signal (simple, mais rustique), ou mieux par
• sigaction (plus complet).
✱
8.2 Concept de signal
peut être masqué ou non, signal par signal, Selon un
masque de signaux propre à chaque processus.
557
(cf. signification précise page ??)
nom
SIGABRT
SIGALRM
SIGBUS
SIGCHLD
SIGCONT
SIGEMT
SIGFPE
SIGHUP
SIGILL
SIGINFO
SIGINT
nom complet
abort
alarm
bus error
child
continue
emulator trap
floating point except.
hangup
illegal instruction
information request
interrupt
catégorie
terminaison
réveil par timer
erreur détectée par le matériel
gestion des travaux (cf. chap. 11)
gestion des travaux (cf. chap. 11)
obsolète (PDP11)
erreur détectée par le matériel
terminaison
erreur détectée par le matériel
gestion des travaux (cf. chap. 11)
terminaison
558
Liste alphabétique des signaux
nom
SIGIO
SIGIOT
SIGKILL
SIGPIPE
SIGPOLL
SIGPROF
SIGPWR
SIGQUIT
SIGSEGV
SIGSTOP
SIGSYS
SIGTERM
nom complet
I/O termination
I/O trap
kill
pipe (or socket)
pollable event
profiling
power
quit
segmentation violation
stop
system call
termination
Liste alphabétique des signaux
suite(1)
catégorie
événement lié aux périphériques
obsolète (PDP11)
terminaison
événement lié aux périphériques
événement lié aux périphériques
réveil par timer
événement lié aux périphériques
terminaison
erreur détectée par le matériel
gestion des travaux (cf. chap. 11)
erreur signalée par le système
terminaison
nom
SIGTRAP
SIGTSTP
SIGTTIN
SIGTTOU
SIGURG
SIGUSR1
SIGUSR2
SIGVTALRM
SIGWINCH
SIGXCPU
SIGXFSZ
nom complet
trap instruction
terminal stop
terminal in error
terminal out error
urgent
user-defined signal 1
user-defined signal 2
virtual time alarm
window changed
cpu time
file size
suite(2)
catégorie
obsolète (PDP11)
gestion des travaux (cf. chap. 11)
gestion des travaux (cf. chap. 11)
gestion des travaux (cf. chap. 11)
événement lié aux périphériques
signal logique
signal logique
réveil par timer
événement lié aux périphériques
erreur signalée par le système
erreur signalée par le système
559
17. SIGNAUX
8.3 Traitement d’un signal
560
17. SIGNAUX
Traitement d’un signal
8.3 Traitement d’un signal
Définition du traitement d’un signal
mécanisme C- ANSI simplifié : signal (3)
✱
✱
le traitement d’un signal peut consister :
• à l’ignorer,
• à utiliser un traitement par défaut,
Syntaxe :
#inlude <signal.h>
void (* signal (int sig, void (* handlingr )(int)))(int);
/* Ou plus lisiblement : */
• à appeler une procédure du processus appelée
traitant
(en anglais handler, ou “signal catching function”).
typedef void (*handler_t)(int);
handler_t signal (int sig, handler_t handling );
✱
Retour :
• OK : traitement précédent,
• erreur : SIG_ERR
561
17. SIGNAUX
8.3 Traitement d’un signal
primitive signal (3)
✱
562
17. SIGNAUX
8.3 Traitement d’un signal
Remarques sur signal (3)
suite(1)
Sémantique :
• associe au signal sig le traitement handling :
une constante prédéfinie dans signal.h ou
nom d’une procédure du processus.
⊲ SIG_IGN : ignorer le signal ;
⊲ SIG_DFL : reprendre le traitement par défaut
(cf. page ??).
⊲ procédure t : exécuter t lors du prochain signal
sig, avec sig en argument.
Cela permet d’associer la même procédure à
plusieurs signaux.
✱
signal est un nom mal choisi : on ne signale rien.
✱
L’association peut être permanente ou valable une seule
fois :
• sous BSD, association permanente jusqu’au prochain
appel à signal ;
• sous U NIX v7 et L INUX, association éphémère, on
reprend le traitement par défaut à chaque traitement
du signal.
Il faut donc réexécuter signal dans le traitant.
563
17. SIGNAUX
8.3 Traitement d’un signal
Remarques sur signal (3)
564
17. SIGNAUX
8.3 Traitement d’un signal
Exemple d’utilisation de signal (3)
suite(1)
✱
signal(3) existait sous U NIX v7, est dans la norme C- ANSI,
mais n’est pas fiable : on ne peut masquer ou démasquer les signaux en même temps, condition de vitesse ou
pertes de signaux possibles.
✱
aujourd’hui signal(3) est implémentée par sigaction
(cf. page ??).
✱
on peut cependant encore utiliser signal(3) dans les cas
simples, assez fréquents.
565
stati void sig_usr (int signo){
/* traitant ommun pour USR1 et USR2 */
if (signo == SIGUSR1) printf("SIGUSR1 reçu\n");
else if (signo == SIGUSR2) printf("SIGUSR2 reçu\n");
else err_dump("signal inattendu %d\n", signo);
return;
}
Remarque :
L’impression par printf dans un traitant est déconseillée (primitive non réentrante).
566
Exemple d’utilisation de signal (3)
Entrée dans un traitant
suite(1)
...
if (signal (SIGUSR1, sig_usr) == SIG_ERR) ERR;
if (signal (SIGUSR2, sig_usr) == SIG_ERR) ERR;
✱
/* Travail du processus plus ou moins long...
dès l’entrée dans le traitant, certains signaux doivent souvent être masqués
(cf. système fiable vs non fiable, page ??),
en particulier celui qui a été émis.
* ou mise en attente : pause, sigsuspend, wait...
* Ce code peut être interrompue par un signal :
Le traitant peut alors :
* USR1, USR2 => exécution du traitant et retour
✱
* INT, QUIT => terminaison par défaut
*/
...
connaître le signal (argument sig) et, sur option, d’autres
informations (identité de l’émetteur..., cf. strut siginfo,
page ??);
567
17. SIGNAUX
8.3 Traitement d’un signal
Entrée dans un traitant
✱
568
17. SIGNAUX
8.3 Traitement d’un signal
Sortie d’un traitant
suite(1)
analyser la cause par d’autres moyens plus précis (appels
systèmes, variable errno, variables globales...) et communiquer de manière synchrone avec d’autre processus,
immédiatement ou plus tard s’il est pressé...
✱
masquer ou démasquer les signaux de son choix,
✱
changer le traitement associé à son signal :
signal, sigaction.
✱
choisir un point de retour (cf. ci-après).
À la fin de son traitement, un traitant de signal
a trois possibilités de débranchement :
1) par exit(3) ou _exit(2) : abandon du travail ;
2) par return : reprise au point d’interruption
(cas le plus fréquent) ;
3) par setjmp / longjmp (cf. chap. 5, page 285),
ou leur variante sigsetjmp / siglongjmp (cf. page ??) :
propagation de l’événement, par débranchement dans
un gestionnaire spécialisé.
569
17. SIGNAUX
8.3 Traitement d’un signal
Sortie d’un traitant
570
17. SIGNAUX
8.3 Traitement d’un signal
Sortie d’un traitant par _exit (2) / exit (3)
suite(1)
Noyau du système
Noyau du système
t (s) + masquage s
t (s) + masquage s
return +
démasquage s
1
main () {
signal (s, t);
manager();
2 traitant t
1
void t (int s){
2
2 traitant t
main () {
exécution
du traitant
pour le
signal s
void t (int s){
signal (s, t);
exécution
du traitant
pour le
signal s
2
exit (0)
signal s
}
manager () {
setjmp(e)
}
exit (1)
return
exit (0)
3
signal s
}
}
}
3 exit (1)
3 sorties
longjmp (e) possibles
Espace mémoire du processus
Espace mémoire du processus
571
17. SIGNAUX
8.3 Traitement d’un signal
Sortie d’un traitant par return
572
17. SIGNAUX
8.3 Traitement d’un signal
Sortie d’un traitant par return
suite(1)
Noyau du système
La terminaison du traitant retourne dans le système qui réalise le débranchement au point d’interruption du signal.
✱
ordinaire : l’exécution se poursuit avec démasquage du
signal émis.
Cela peut provoquer un retour dans le traitant, si ce signal
était en suspens.
un appel système ...
+
démasquage s
1
Deux cas à distinguer, selon que l’instruction interrompue est:
✱
return
t (s) + masquage s
main () {
signal (s, t);
2 traitant t
void t (int s){
exécution
du traitant
pour le
signal s
2
exit (0)
signal s
}
3 return
}
Espace mémoire du processus
573
574
Sortie d’un traitant par return
Sortie d’un traitant à un endroit spécifique
suite(2)
Lorsqu’un appel système est interrompu, il est (au choix) :
✱
automatiquement relancé : l’appel se terminera comme
s’il n’avait pas été interrompu.
✱
ou mis en échec avec CR == -1 et errno == EINTR.
L’exécution se poursuit avec un démasquage du signal
émis, sauf pour sigsuspend (cf. page ??) où le masque est
rétabli comme il était au moment de l’appel à sigsuspend.
Cela permet de se débrancher à un gestionnaire qui propage
l’événement reçu à un module (ou classe) qui est “hiérarchiquement responsable”
✱
par setjmp et longjmp, sans modification du masque des
signaux en cours, à la fin du traitant,
✱
(cf. page ?? pour une discussion complète sur ce phénomène).
ou par les variantes sigsetjmp / siglongjmp , pour une restauration du masque des signaux dans l’état qu’il avait au
moment de sigsetjmp.
575
576
17. SIGNAUX
8.3 Traitement d’un signal
17. SIGNAUX
8.4 Signalement explicite
Envoi d’un signal par kill (2)
Sortie d’un traitant à un endroit spécifique
suite(1)
Noyau du système
✱
t (s) + masquage s
int kill (pid_t pid, int signo );
1
main () {
signal (s, t);
2
if (setjmp(e)==0){
travail ( );
exit (0)
} else {
traitement du
problème
exit (1);
}
travail ( ) {
2
signal s
}
return ;
Syntaxe :
#inlude <sys/types.h> #inlude <signal.h>
✱
Retour :
• 0, si OK ,
• -1, si erreur : le(s) processus n’existe(nt) pas (plus)
✱
Sémantique :
• émet le signal de nom signo au(x) processus spécifié(s) par pid.
On définit signo par une constante SIGXXXX plutôt
qu’un entier.
traitant t
void t (int s){
exécution
du traitant
pour le
signal s
longjmp (e, k)
3
}
setjmp (env)
longjmp(env, int)
Espace mémoire du processus
578
577
17. SIGNAUX
8.4 Signalement explicite
kill (2)
✱
17. SIGNAUX
8.4 Signalement explicite
Restrictions pour kill (2)
suite(1)
Selon pid, le signal est émis à :
• pid > 0 : au processus de pid donné ;
• pid == 0 : à tous les processus du groupe de
l’émetteur ;
✱
Si le processus émetteur est non SU , son RUID ou EUID
doit être le RUID ou SUID du processus receveur.
✱
L’émetteur peut envoyer un signal aux processus de la
même session (à ses fils, même s’ils ont un EUID différent) ou à des processus d’une autre session, mais appartenant au même utilisateur.
✱
L’émetteur ne peut envoyer un signal à un processus d’un
autre utilisateur.
=> on ne peut pas utiliser des signaux
pour une architecture client-serveur !
• pid < 0 : à tous les processus du groupe du processus | pid | ;
• pid == -1 : à tous les processus (sauf l’émetteur) du
propriétaire de l’émetteur.
Si l’émetteur est SU , c’est une diffusion (broadcasting) à tous les processus (sauf l’emetteur, e.g.
shutdown).
579
17. SIGNAUX
8.4 Signalement explicite
Restrictions pour kill
580
17. SIGNAUX
8.4 Signalement explicite
Restrictions pour kill
suite(1)
suite(2)
✱
Si le processus émetteur est SU , il peut émettre un signal
à n’importe quel autre processus.
✱
Le signal de numéro 0 n’envoit rien, mais sert à tester
l’existence de processus.
✱
kill peut émettre n’importe quel signal, même ceux émis
normalement par le matériel ou le système :
utile pour les tests.
✱
✱
SIGCONT ne peut être émis qu’à des processus de la même
session.
La commande kill(1) ne fait qu’appeler kill ; elle sert à
envoyer n’importe quel signal à un ou plusieurs processus, généralement pour les tuer...
(d’où ce nom mal choisi !).
581
582
États d’un signal
États d’un signal
suite(1)
Pour un processus donné, chaque signal peut être dans les
états suivants (non exclusifs) :
✱
associé à un traitement :
par défaut ou choisi (par signal ou sigaction) ;
✱
masqué (ou bloqué) ou démasqué (débloqué) :
traitable ou non par le processus ;
✱
émis (ou envoyé) à un processus :
lorsque l’événement se manifeste ;
cela est noté par le noyau dans le descripteur du processus ;
✱
en attente :
émis, non masqué, pas encore traité ;
✱
en suspens (pending) :
émis et masqué, donc pas encore traité.
✱
notifié :
délivré à un traitant, en cours de traitement particulier,
✱
traité :
ignoré, traité par défaut ou par un traitant particulier;
583
17. SIGNAUX
8.5 États d’un signal
Descripteurs associés aux signaux
584
17. SIGNAUX
Descripteurs associés aux signaux
suite(1)
champs divers du processus :
Champs pour les signaux dans le descripteur d’un processus :
✱
8.5 États d’un signal
pid, ppid, group, files...
descripteur
de processus
...
ITIMER_REAL
ITIMER_VIRTUAL
un tableau des signaux émis : (en attente ou en suspens)
un tableau de bits ou de files de signaux; l’émission d’un
signal i met son bit à 1, son traitement le remet à 0.
ITIMER_PROF
signaux
émis
masque
table des
traitements
sighup
sig int
sigkill
✱
✱
un masque de signaux :
un ensemble des signaux masqués, e.g. un tableau de
bits;
sigalrm
sigterm
...
...
...
un tableau des traitements des signaux :
e.g. des constantes ou des adresses des traitants.
585
17. SIGNAUX
8.5 États d’un signal
586
17. SIGNAUX
8.5 États d’un signal
Notification d’un signal
Émission d’un signal
L’émetteur d’un signal (cf. page ??) peut être :
✱
le système lui-même,
✱
un autre processus par kill(2) ou la commande kill(1),
✱
le matériel,
✱
une horloge (timer),
✱
une touche du terminal de contrôle (TC , cf. chap. 11).
La notification d’un signal à un processus
(mise à jour de son descripteur)
est toujours faite par le système,
qui peut recevoir des interruptions du matériel ou
des appels système (kill).
Le système peut diffuser un signal à plusieurs processus
(groupes) par une itération de son émission.
587
17. SIGNAUX
8.5 États d’un signal
Cause d’un signal
normale (changement de taille de fenêtre...)
✱
anormale (division par 0...)
17. SIGNAUX
8.5 États d’un signal
Mémorisation des signaux
La plupart des systèmes U NIX ne mémorisent au plus qu’une
occurrence pour chaque numéro de signal en suspens :
tableau de bits, pas un tableau de files !
(si un signal est émis plusieurs fois avant d’être traité,
il ne sera notifié qu’une seule fois).
La cause d’un signal peut être :
✱
588
Cela explique les traitements par défaut (cf. page ??).
Un usage fréquent des signaux est d’arrêter, stopper ou faire
repartir un processus...
Lorsqu’un processus a plusieurs signaux différents en attente,
le choix d’un signal à traiter par le noyau est indéfini :
pas de priorité entre les signaux.
589
590
Mémorisation des signaux
Précautions à prendre
dans les traitants de signaux
suite(1)
Lorsqu’un traitant est exécuté, il faut prendre garde à :
Sauf si le système est très chargé, un signal ne reste pas
longtemps en attente :
il est notifié dès que possible par le céduleur.
✱
ce qu’il ne soit pas interrompu par le même numéro de signal envoyé immédiatement après, ou par un autre signal
indésirable.
✱
ne pas appeler de fonctions non réentrantes (cf. plus loin)
qui pourraient être actives au moment du déroutement
dans le traitant : primitive système ou de bibliothèque,
fonction propre au processus.
✱
à ne pas perdre de signaux : ignorer involontairement un
signal émis.
Un signal reste en suspens pour un processus, tant que ce
processus existe et qu’il ne l’a pas démasqué ou ignoré.
Un processus peut changer le traitement associé à des signaux en suspens : l’ignorer, revenir à son traitement par défaut, changer son traitement.
591
17. SIGNAUX
8.6 Signification des signaux
592
17. SIGNAUX
Signification des signaux
Signification des signaux
Signaux de terminaison :
Nom
SIGKILL
SIGTERM
SIGINT
action par déf.
termine
termine
termine
SIGABRT
termine + core
SIGQUIT
termine + core
8.6 Signification des signaux
suite(1)
Signaux de terminaison :
Effet
terminaison immédiate et autoritaire
demande de terminaison
demande
de
terminaison par touche,
e.g. trl demande de terminaison + core,
cf. abort(3)
demande
de terminaison + core, e.g.
trl \
Nom
SIGHUP
action par déf. Effet
termine
•déconnexion de la ligne d’accès :
envoi au leader de session (option
ioctl) ;
•terminaison du leader de session :
envoyé à ses fils ;
•envoi à un démon (pas de TC ) :
demande de relecture du ficher de
configuration.
593
17. SIGNAUX
8.6 Signification des signaux
Signification des signaux
594
17. SIGNAUX
8.6 Signification des signaux
Signification des signaux
suite(2)
suite(3)
Gestion des travaux (job system), cf. chap. 11 :
Nom
SIGSTOP
SIGTSTP
trl z
Réveils par timer : cf. alarm, setitimer, getitimer :
Nom
SIGALRM
SIGVTALRM
SIGPROF
action par déf.
termine
termine
termine
action par déf. Effet
stop
stop autoritaire
stop
demande
stop par clavier,
SIGCONT
SIGCHLD
Effet
temps réel de la montre (µsec)
temps cpu du processus (µsec)
temps cpu pour profilage (µsec)
SIGTTIN
SIGTTOU
SIGINFO
continue/ignore redémarrage après stop
ignore
terminaison, stop ou redémarrage
d’un fils
stop
tentative de lire le TC en background
stop
tentative d’écrire sur le TC en background
ignore
demande
de
statut par clavier (BSD),
e.g. trl t
595
17. SIGNAUX
8.6 Signification des signaux
Signification des signaux
e.g.
596
17. SIGNAUX
8.6 Signification des signaux
Signification des signaux
suite(4)
suite(5)
Erreurs signalées par le système :
Nom
SIGSYS
SIGXCPU
SIGXFSZ
Signaux logiques (utilisateur ou programmes) :
action par déf. Effet
termine + core argument erroné, appel système inconnu
termine + core limite de temps dépassée cf. getrlimit
termine + core limite de taille fichier dépassée cf. getrlimit
Nom
SIGUSR1
SIGUSR2
597
action par déf. Effet
termine
signal logique n◦1
termine
signal logiciel n◦2
598
Signification des signaux
Signification des signaux
suite(6)
suite(7)
Événements liés aux périphériques :
Nom
SIGPIPE
Erreurs détectées par le matériel :
action par déf. Effet
termine
tentative d’écriture avec personne
pour lire
termine/ignore fin d’E/S asynchrone (BSD), cf. fcntl
termine
événement d’E/S sélectionnable
(SVR4), cf. poll
ignore
condition urgente sur socket
ignore
changement taille fenêtre,
cf. termio(4), win(4S)
ignore
coupure de courant électrique
(SVR4)
SIGIO
SIGPOLL
SIGURG
SIGWINCH
SIGPWR
Nom
SIGBUS
SIGSEGV
SIGFPE
action par déf.
termine + core
termine + core
termine + core
SIGILL
termine + core
Effet
indéterminée ( vient du PDP-11)
adressage
arithmétique entière ou flottante :
div.
par 0, sur- ou sousdébordement...
instruction machine inconnue
(possible en assembleur)
599
17. SIGNAUX
8.6 Signification des signaux
Signification des signaux
600
17. SIGNAUX
8.6 Signification des signaux
Signaux : émetteur et normes
suite(8)
Nom
SIGABRT
SIGALRM
SIGBUS
SIGCHLD
SIGCONT
SIGEMT
SIGFPE
SIGHUP
SIGILL
SIGINFO
SIGINT
SIGIO
Signaux obsolètes (origine du PDP-11) :
Nom
SIGEMT
SIGIOT
SIGTRAP
action par déf.
termine + core
termine + core
termine + core
Effet
émulateur d’instructions (flottant...)
trappe d’E/S
instruction trappe
Emetteur
Présent dans norme
d’origine C ANSI POSIX SVR4 BSD4.4
kill
•
•
•
•
timer
•
•
•
hard
•
•
syst
•
•
•
kill
•
•
•
hard
•
•
hard
•
•
•
•
TC
•
•
•
hard
•
•
•
•
TC
•
TC
•
•
•
•
hard
•
•
601
17. SIGNAUX
8.6 Signification des signaux
Signaux : émetteur et normes
Nom
SIGIOT
SIGKILL
SIGPIPE
SIGPOLL
SIGPROF
SIGPWR
SIGQUIT
SIGSEGV
SIGSTOP
SIGSYS
SIGTERM
602
17. SIGNAUX
8.6 Signification des signaux
Signaux : émetteur et normes
suite(1)
suite(2)
Nom
Emetteur
Présent dans norme
d’origine C ANSI POSIX SVR4 BSD4.4
SIGTRAP
hard
•
•
SIGTSTP
TC
•
•
•
SIGTTIN
TC
•
•
•
SIGTTOU
TC
•
•
•
SIGURG
hard
•
•
SIGUSR1
kill
•
•
•
SIGUSR2
kill
•
•
•
SIGVTALRM
timer
•
•
SIGWINCH
hard
•
•
SIGXCPU
syst
•
•
SIGXFSZ
syst
•
•
Emetteur
Présent dans norme
d’origine C ANSI POSIX SVR4 BSD4.4
hard
•
•
kill
•
•
•
syst
•
•
•
hard
•
timer
•
•
hard
•
TC
•
•
•
hard
•
•
•
•
kill
•
•
•
syst
•
•
kill
•
•
•
•
Dans ce cours, ne retenir que les signaux POSIX
603
17. SIGNAUX
8.6 Signification des signaux
Connaître le nom des signaux :
sys_siglist, psignal (3)
✱
604
17. SIGNAUX
8.6 Signification des signaux
Connaître le nom des signaux
✱
Syntaxe :
#inlude <signal.h>
extern har* sys_siglist [℄;
extern int sys_nsig ;
suite(1)
Sémantique :
• sys_siglist : tableau de noms de signaux, indexé
par les numéros de signaux.
Cela permet d’afficher des messages indiquant
l’identité en clair des signaux reçus.
• sys_nsig : nombre de signaux définis sur le système : 48 sur OSF1, 45 sur Solaris, 32 sur Linux...
void psignal (int signo, onst har* msg ){
printf ( "%s: %s\n",
mess, sys_siglist[signo℄);
}
• psignal : fonction analogue à perror .
• Ces facilités ne sont pas dans la norme POSIX :
cf. signal.h pour connaître ce qui est disponible.
605
606
Envoi d’un signal au processus lui-même :
raise (3)
✱
Syntaxe :
#inlude <sys/types.h> #inlude <signal.h>
int raise (int signo);
✱
Retour :
• 0, si OK ,
• -1, si erreur
✱
Sémantique :
• émet le signal signo au processus lui-même.
donc équivalent à kill (getpid(), signo);
• primitive C- ANSI : MSDOS (monoprocessus)...
Envoi du signal SIGABRT : abort (3)
✱
Syntaxe :
#inlude <stdlib.h> void abort (void);
✱
Retour : pas de retour : terminaison,
✱
Sémantique :
• émet le signal SIGABRT au processus lui-même.
donc équivalent à : kill (getpid(), SIGABRT);
• SIGABRT écrit un dump mémoire dans le fichier
core pour les débogueurs comme adb, dbx, gdb...
• un traitant de SIGABRT ne doit pas se terminer par
return ; utiliser : exit(3), longjmp(3), siglongjmp(3)
607
17. SIGNAUX
8.8 Réveils avec horloge
608
17. SIGNAUX
Réveils avec horloge (timer)
8.8 Réveils avec horloge
Réveils avec horloge (timer)
suite(1)
✱
ITIMER_REAL : correspond au temps réel externe (montre)
et émet le signal SIGALRM.
✱
ITIMER_VIRTUAL : correspond au temps virtuel du processus seul (temps CPU) et émet le signal SIGVTALRM.
✱
Lorsqu’un compteur atteint la valeur 0 au bout d’un intervalle
de temps, le système émet un signal propre à chaque compteur...
ITIMER_PROF : correspond au temps virtuel complet (temps
CPU du processus + des appels systèmes du processus)
et émet le signal SIGPROF.
Ce signal est utilisé, avec SIGVTALRM, principalement par
les outils de profilage par échantillonnage temporel, qui
estiment le temps passé dans les différentes parties d’un
programme.
609
610
Chaque processus dispose de 3 horloges de réveil distinctes,
implémentées par des compteurs qui se décrémentent avec
une fréquence maximum de une µ-seconde
(dans les premiers système, une seconde).
17. SIGNAUX
8.8 Réveils avec horloge
Structure d’une horloge de réveil : struct
itimerval
✱
17. SIGNAUX
8.8 Réveils avec horloge
Structure d’une horloge de réveil
✱
Syntaxe :
#inlude <sys/time.h>
strut itimerval {
strut timeval it_interval ; /* fréquence */
strut timeval it_value ; /* valeur restante */
}
strut timeval {
long tv_se; /* secondes */
long tv_use; /* µ-secondes */
};
suite(1)
Sémantique :
• Chaque timer est une strut itimerval qui contient
deux compteurs :
⊲ it_interval : l’intervalle de temps demandé lors
du dernier setitimer (par défaut 0).
⊲ it_value : l’intervalle de temps restant avant la
prochaine émission du signal.
• Le timer décrémente it_value et émet un signal
lorsque cette valeur atteint zéro.
• La valeur de it_value est alors réinitialisée avec
it_interval.
611
17. SIGNAUX
8.8 Réveils avec horloge
Structure d’une horloge de réveil
✱
612
17. SIGNAUX
8.8 Réveils avec horloge
Structure d’une horloge de réveil
suite(2)
Sémantique : (suite)
• Un timer est actif (génère des signaux) tant que son
champ it_interval indique un temps non nul ; il est
inactif (stoppé) sinon.
• Les signaux ne sont jamais émis avant les délais
demandés. Ils sont émis après le délai demandé +
une constante de réflexe dépendant du système (de
l’ordre de 10ms).
613
✱
suite(3)
Sémantique : (suite)
• Lorsque le processus est actif et que le délai d’un
timer expire :
⊲ le signal SIGVTALRM est émis immédiatement,
⊲ après un court délai dépendant de la charge du
système pour les signaux SIGALRM et SIGPROF.
614
setitimer
Armement d’une horloge de réveil :
suite(1)
setitimer (2)
✱
✱
✱
Syntaxe :
#inlude <sys/time.h>
int setitimer (int whih,
onst strut itimerval* value,
strut strut itimerval* value );
};
Sémantique :
• which indique, par une constante symbolique
ITIMER_REAL, ITIMER_VIRTUAL ou ITIMER_PROF, quel
compteur est initialisé.
• value indique l’intervalle de temps demandé (seul le
champ it_interval est nécessaire);
Retour :
• 0, si OK ,
• -1, si erreur
• ovalue, s’il est non NULL, reçoit la valeur courante du
timer avant la réinitialisation.
615
17. SIGNAUX
8.8 Réveils avec horloge
616
17. SIGNAUX
8.8 Réveils avec horloge
getitimer
Consultation d’une horloge de réveil :
suite(1)
getitimer (2)
✱
✱
Syntaxe :
#inlude <sys/time.h>
int getitimer (int whih,
strut itimerval* value );
};
✱
Sémantique :
• which indique, par une constante symbolique
ITIMER_REAL, ITIMER_VIRTUAL ou ITIMER_PROF, quel
compteur est initialisé.
• value récupère les deux compteurs du timer demandé, avec leurs valeurs actuelles :
⊲ it_interval : période actuelle d’émission du signal,
Retour :
• 0, si OK ,
• -1, si erreur
⊲ it_interval : durée restante avant le prochain signal, 0 si le timer est inactif.
617
17. SIGNAUX
8.8 Réveils avec horloge
618
17. SIGNAUX
8.8 Réveils avec horloge
alarm (3)
Armement simplifié de l’horloge de réveil :
suite(1)
alarm (3)
✱
Syntaxe :
#inlude <unistd.h>
unsigned int alarm ( unsigned int seonds );
✱
Retour :
• nb de sec. restantes, avant prochain SIGALRM.,
• 0, si l’horloge ITIMER_REAL est inactive.
✱
✱
Sémantique :
• Si seconds = 0, ITIMER_REAL est désactivé ;
• alarm(3) est implémenté avec setitimer qui modifie
ITIMER_REAL ;
• alarm(3) existait dès U NIX v7 ; elle reste d’actualité
(POSIX), par sa grande simplicité ;
Sémantique :
• Initialise ITIMER_REAL avec le temps en sec ;
• Bien que la précision soit grossière (seconde), cette
primitive reste réaliste pour les systèmes chargés.
Remarque : la nouvelle primitive ualarm(3) tient compte de la vitesse des
processeurs actuels (micro-secondes).
619
17. SIGNAUX
8.9 Mise en attente d’un processus
620
17. SIGNAUX
Mise en attente d’un processus
8.9 Mise en attente d’un processus
Mise en attente d’un processus
Pour sa logique propre, un processus doit souvent, pour se
synchroniser, attendre un événement externe :
✱
la terminaison d’un processus fils : wait, waitpid... ;
✱
une fin d’E/S : les primitives sont souvent blocantes, avec
attente automatique de la fin ;
suite(1)
✱
un intervalle de temps déterminé : nanosleep(3), sleep(3) ;
✱
un ou plusieurs événements quelconques signalés par un
signal, par une attente volontaire :
• active, infinie ou bornée, par l’exécution d’instructions
inoffensives,
il existe une possibilité d’E/S non bloccantes, asynchrones, qui en-
• passive, par un appel système :
pause(3), sigsuspend,
voient un signal SIGIO à la fin de l’E/S.
• passive bornée : sleep(3), nanosleep(3).
Remarque :
621
622
Attente volontaire active, indéfinie
Attente volontaire active indéfinie
suite(1)
Réalisée par une boucle « infinie », de durée indéfinie,
sans effet sur le programme.
Attente indéfinie :
stati jmp_buf env;
...
if (setjmp (env) == 0) {
Inconvénients :
/* Mise en attente active */
for ( ; ; ) ;
✱
très mauvaise utilisation du processeur de calcul,
✱
programmation compliquée.
}
/* reprise après un signal dont le traitant
* se termine par longjmp(env) */
...
623
17. SIGNAUX
8.9 Mise en attente d’un processus
624
17. SIGNAUX
Attente volontaire active bornée
8.9 Mise en attente d’un processus
Attente volontaire active bornée
suite(1)
Attente limitée correcte
Attente limitée erronée : fenêtre de temps
stati jmp_buf env; stati int i;
...
if (setjmp (env)==0) {/* mise en attente ative */
for (i= 200000000 ; i > 0 ; i--) ;
}
stati int i;
/* Mise en attente ative */
for (i= 200000000 ; i > 0 ; i--) ;
/* reprise après un signal dont le traitant
* se termine par i=0;
/* reprise après un signal dont le traitant
* => fenêtre de temps ! */
* se termine par longjmp(env) */
...
...
625
17. SIGNAUX
8.9 Mise en attente d’un processus
Attente volontaire active bornée
programmation compliquée,
✱
durée limitée mais liée au processeur.
17. SIGNAUX
8.9 Mise en attente d’un processus
Attente volontaire passive : pause (3)
suite(2)
Inconvénients :
✱ très mauvaise utilisation du processeur de calcul,
✱
626
✱
Syntaxe :
#inlude <unistd.h>
int pause (void);
✱
Retour :
• Jamais OK, appel interrompu (cf. page ??),
• -1, si erreur, avec errno == EINTR
✱
Sémantique :
• Le noyau laisse le processus oisif (idle), tant qu’il
ne reçoit pas un signal ; cela ne consomme pas de
CPU pour le processus.
627
17. SIGNAUX
8.9 Mise en attente d’un processus
pause (3)
✱
628
17. SIGNAUX
8.9 Mise en attente d’un processus
pause (3)
suite(1)
suite(2)
Sémantique (suite) :
• Le processeur peut être utilisé pour d’autres processus...
• À la réception d’un signal, 2 cas possibles, selon
son traitement :
⊲ traitant qui se termine par return : poursuite du
traitement, après la primitive pause.
CR == -1, errno == EINTR.
✱
Avantages : bonne utilisation du CPU, programmation
facile, mais non sans dangers (cf. pages ??).
✱
Inconvénients : ne masque pas les signaux en même
temps contrairement à sigsuspend (cf. page ??).
⊲ traitement par défaut qui termine ou traitant qui
exécute exit : le processus se termine.
629
630
sleep (3)
Attente volontaire passive bornée : sleep (3)
✱
✱
Syntaxe :
#inlude <unistd.h>
unsigned int sleep (unsigned int seonds )) ;
✱
Retour :
• 0 réveil par temps épuisé ,
• >0 réveil par signal, nb de sec. qui restent
✱
Sémantique :
• attente comme pause, mais pour une durée limitée
en secondes.
suite(1)
Sémantique (suite) :
• réveil obtenu par le premier des deux :
⊲ le temps demandé est écoulé,
⊲ un signal a été émis au processus.
Dans ce cas, il est traité comme pause, avec un
retour juste après sleep (traitant qui retourne) ou
une terminaison.
• sleep(3) est implémentée avec alarm (cf. p. ??).
Remarque : la nouvelle primitive usleep(3) tient compte de la vitesse des
processeurs actuel (micro-secondes)...
631
17. SIGNAUX
8.9 Mise en attente d’un processus
632
17. SIGNAUX
8.9 Mise en attente d’un processus
nanosleep (3)
Attente volontaire précise : nanosleep (3)
✱
✱
Syntaxe :
#inlude <time.h>
int nanosleep ( onst strut timespe * req,
strut timespe * rem );
strut timespe {
time_t tv_se; /* seonds */
long tv_nse; /* nanoseonds */
}
✱
suite(1)
Sémantique :
• Identique à sleep(3), sauf pour la précision qui descend très en dessous de la sec. : selon la précision
de l’horloge, actuellement 1 à 10 ms, mais encore
très loin de 1 ns !
• req est la limite de l’attente demandée,
• Si rem 6= NULL, la structure pointée reçoit la durée
restant à attendre au moment du réveil (0 si temps
épuisé).
Retour :
• 0 : réveil par temps épuisé,
• -1 et errno == EINTR : interruption par signal.
-1 et errno == EINVAL : req.tv_se aberrant.
633
17. SIGNAUX
8.10 Problèmes avec les signaux
634
17. SIGNAUX
8.10 Problèmes avec les signaux
Manque de fiabilité
Manque de fiabilité
des anciens systèmes Unix
des anciens systèmes Unix
suite(1)
Pour corriger ce défaut, les systèmes BSD et SVR4 ont proposé des primitives aujourd’hui obsolètes :
Pour être fiable, un traitant doit disposer d’opérations atomiques, donc avec certains signaux masqués.
U NIX version 7 ne disposait que d’une version non fiable de
la primitive signal, sans possibilité de masquage.
635
17. SIGNAUX
8.10 Problèmes avec les signaux
Fiabilité des systèmes POSIX
✱
SVRX : sigset, sighold, sigrelse, sigignore, sigpause
✱
BSD4.X :
sigvec, sigblock, sigsetmask, sigpause,
De plus, les comportements de ces systèmes à l’entrée ou à
la sortie d’un traitant varient :
✱
maintient de l’association du traitant,
✱
redémarrage automatique des appels système interrompus
636
17. SIGNAUX
8.10 Problèmes avec les signaux
Fiabilité des systèmes POSIX
suite(1)
Aujourd’hui, les systèmes U NIX sont à la norme POSIX.
Celle-ci a un mécanisme de signaux fiables, avec masquage
possible par quatre primitives (cf. plus page ??)
✱
sigaction : pour associer un traitant à un signal, avec masquage atomique ;
✱
sigprocmask : pour connaître ou modifier le masque ;
✱
sigpending : pour connaître les signaux en suspens ;
✱
sigsuspend : pour mettre le processus en attente avec
démasquage atomique.
637
La primitive signal est encore très utilisée à la place de sigaction, pour sa grande simplicité.
Mais il faut s’en méfier car toutes les implémentations n’ont
pas un comportement identique et fiable : vérifier que le traitant masquera au moins le signal d’appel.
638
Défauts de la primitive signal (3)
Défauts de la primitive signal (3)
Pour les versions de signal (U NIX v7, Linux...) qui ont une association (signal/traitant) valable une seule fois, il faut souvent
rétablir l’association dans le traitant :
suite(1)
stati sig_int ( int signo ) { /* traitant */
/* Refaire l'assoiation pour prohain signal */
/* B : fenêtre de temps si signo non masqué ! */
signal (SIG_INT, sig_int);
...
}
...
signal (SIGINT, sig_int); /* A */
...
Remarque :
L’appel à signal(3) dans le traitant établissait une fenêtre de temps en U NIX
version 7 : le signal SIGINT pouvait être émis à nouveau entre les points A
et B.
=> dans ce cas, le signal était perdu.
639
17. SIGNAUX
8.10 Problèmes avec les signaux
640
17. SIGNAUX
Non atomicité avec pause
Non atomicité du masquage des signaux
avec pause
suite(1)
...
signal (SIGINT, sig_int); /* A */
...
while ( ! sig_int_flag ){
/* B : fenêtre de temps !! */
pause (); /* C */
...
La version suivante tente de mettre en attente un processus
jusqu’à ce qu’un signal arrive :
int sig_int_flag ; /* inrémenté par le traitant */
stati void sig_int(int signo){
sig_int_flag ++;
}
8.10 Problèmes avec les signaux
Le signal attendu peut être notifié au point B.
S’il n’est émis qu’une fois, le processus restera bloqué en C.
641
17. SIGNAUX
8.10 Problèmes avec les signaux
642
17. SIGNAUX
Non atomicité avec pause :
8.10 Problèmes avec les signaux
sleep1, implémentation incorrecte de
sleep (3) suite(1)
sleep1, implémentation incorrecte de sleep (3)
unsigned int sleep1 ( unsigned int nses) {
if (signal (SIGALRM, sig_alrm) == SIG_ERR)
return(nses);
Soit la version naïve suivante de la primitive sleep(3) :
alarm (nses); /* démarre le timer */
/* fenêtre de temps A */
void sig_alrm (int signo){
/* rien à faire, juste retourner pour réveiller la pause */
return;
}
pause (); /* attend le signal SIGALRM */
/* déative le timer et rend son temps restant */
return (alarm (0));
}
Le signal SIGALRM peut être émis en A, en blocant le processus...
643
17. SIGNAUX
8.10 Problèmes avec les signaux
Non atomicité avec pause :
644
17. SIGNAUX
8.10 Problèmes avec les signaux
sleep2, implémentation incorrecte de
sleep (3) suite(1)
sleep2, implémentation incorrecte de sleep (3)
Autre version incorrecte de sleep(3) avec setjmp :
stati jmp_buf env_alrm;
unsigned int sleep2 ( unsigned int nses ){
if (signal (SIGALRM, sig_alrm) == SIG_ERR)
return(nses);
if (setjmp (env_alrm) == 0) {
alarm (nses); /* démarre le timer */
pause (); /* attend le signal SIGALRM */
}
return (alarm (0)); /* déative le timer, rend le temps restant */
}
645
void sig_alrm (int signo){ longjmp (env_alrm, 1); }
L’astuce est d’utiliser setjmp / longjmp pour garantir l’absence
de blocage, quelles que soient les conditions de vitesse.
C’est mieux, mais il y a encore un problème...
646
Exemple d’utilisation de sleep2
sleep2, implémentation incorrecte de
sleep (3) :
exemple d’utilisation de sleep2
suite(2)
stati void sig_int (int signo){
int i;
volatile int j;
... car le retour par longjmp dans sleep2 peut faire échouer
un autre traitant interrompu par SIGALRM...
...
unsigned int unslept;
if (signal (SIGINT, sig_int) == SIG_ERR) ERR;
unslept = sleep2(5);
printf("temps restant: %u\n", unslept);
...
suite(3)
printf("\nsig_int starting\n");
for (i = 0; i < 2000000; i++) /* attente ative */
j += i * i;
printf("fin de sig_int...\n"); /* A */
return;
}
Ici, la sortie en A est très incertaine...
647
17. SIGNAUX
8.10 Problèmes avec les signaux
Schéma d’utilisation de sleep2
648
17. SIGNAUX
8.10 Problèmes avec les signaux
Interruption d’un appel système
par un signal
suite(4)
On distingue deux types d’appels systèmes :
✱
rapides ou ininterruptibles : ne peuvent se bloquer que
pendant un temps borné et court.
Exemple : read sur un fichier disque.
✱
lents ou interruptibles : peuvent être bloqués plusieurs
secondes, voire plusieurs jours...
Exemple : read sur un terminal, une ligne du réseau, demande d’action nécessitant une intervention humaine...
figure à faire :
figures/schema-utilisation-sleep2.eps
649
17. SIGNAUX
8.10 Problèmes avec les signaux
Interruption d’un appel système
650
17. SIGNAUX
8.10 Problèmes avec les signaux
Interruption d’un appel système
suite(1)
Lorsqu’un signal est émis à un processus bloqué sur un appel
système lent, il peut être judicieux d’interrompre le blocage
en :
✱
exécutant un traitant associé au signal,
✱
puis en faisant échouer l’appel système interrompu,
✱
puis en reprenant juste après son lancement, si le traitant
termine par return (CR == -1, errno == EINTR) ;
✱
ou en terminant le processus, si le traitant termine par
exit.
suite(2)
Programmation explicite de la reprise
Cela oblige la programmation des appels systèmes lents à
être plus compliquée pour traiter ces cas d’échecs :
again:
if ((n= read (term, buff, BSIZE)) <0 )
if (errno == EINTR) /* appel syst. interrompu */
goto again;
else /* autres erreurs ...*/
ERR;
651
17. SIGNAUX
8.10 Problèmes avec les signaux
Interruption d’un appel système
652
17. SIGNAUX
8.10 Problèmes avec les signaux
Interruption d’un appel système
suite(3)
suite(4)
Reprise automatique
Pour simplifier cette programmation, POSIX permet une reprise automatique des appels systèmes lents, mais sur option à fournir pour chaque signal avec sigaction (cf. page ??).
Appels système rapides : ininterruptibles (atomiques)
Tous les appels dont la durée d’exécution est bornée, notamment les E/S avec un disque : read, write, open...
(blocage éphémère)
if ((n= read (term, buff, BSIZE)) <0 ) ERR;
653
654
Interruption d’un appel système
Déblocage d’une primitive lente
avec time out, sans masquage des signaux
suite(5)
Appels système lents : interruptibles
✱
read ou write sur un tube, un terminal, un appareil du
réseau...
Pour se prémunir d’un blocage de lecture du clavier :
...
int n; har line[MAXLINE℄;
if(signal (SIGALRM, talrm)==SIG_ERR) ERR;
alarm (10); /* fenêtre de temps A */
if ( (n=read (0, line, MAXLINE)) < 0) ERR;
alarm (0);
write (STDOUT_FILENO, line, n);
...
(en système V, cela correspond à des stream devices).
✱
open, lorsqu’il peut se bloquer : un modem par exemple.
✱
certains ioctl, comme rembobiner une bande magnétique
en pause manuelle ;
✱
certaines primitives IPC,
✱
pause, sigsuspend, wait, waitpid, wait3 ou wait4 dont la
vocation est justement de bloquer le processus pendant
une durée indéterminée...
655
17. SIGNAUX
8.10 Problèmes avec les signaux
656
17. SIGNAUX
Débloquer une primitive lente avec time out
8.10 Problèmes avec les signaux
Problème de réentrance
(primitive système ou non)
suite(1)
processus
fonction f () {
stati void talrm (int signo){
return; /* juste retourner pour débloquer le read */
}
noyau
1er p ( )
primitive p( ) {
s
}
Le signal SIGALRM peut être émis en A, n’empêchant pas le
blocage éventuel.
Si l’appel read est rédémarré automatiquement
(cf. page ??) le signal SIGALRM est sans effet...
traitant t (int s) {
1er p ( )
2e p ( )
2e p ( )
} return
}
return
2 appels qui se
chevauchent
657
17. SIGNAUX
8.10 Problèmes avec les signaux
658
17. SIGNAUX
Réentrance des primitives système
8.10 Problèmes avec les signaux
Réentrance des primitives système
suite(1)
Si un traitant appelle une routine (procédure ou fonction du
système, de bibliothèque ou propre au processus), celle-ci
doit être réentrante :
Les primitives non réentrantes sont :
✱
si cette primitive était en cours d’exécution au moment de
l’émission du signal,
✱
et a été interrompue par l’activation du traitant,
✱
l’exécution de la primitive par le traitant (il réentre dans la
primitive) doit donner un résultat correct,
✱
et lors de la fin du traitant, le retour dans la primitive doit
aussi donner un résultat correct.
✱
interruptibles et utilisent la mémoire du processus :
bss, data, heap.
✱
exemples : malloc ou free (ou celles qui les utilisent), et
les primitives C- ANSI d’E/S (printf, getchar...).
659
17. SIGNAUX
8.10 Problèmes avec les signaux
660
17. SIGNAUX
Appels système garantis réentrants :
8.10 Problèmes avec les signaux
Appels système garantis réentrants
suite(1)
(appelables depuis un traitant de signal )
_exit
abort
access
alarm
cfgetispeed
cfgetospeed
cfsetispeed
cfsetospeed
chdir
chmod
chown
fork
fstat
getegid
geteuid
getgid
getgroups
getpgrp
getpid
getppid
getuid
kill
pipe
read
rename
rmdir
setgid
setpgid
setsid
setuid
sigaction
sigaddset
sigdelset
close
creat
dup
dup2
execle
execve
fcntl
stat
sysconf
tcdrain
tcflow
tcflush
tcgetattr
tcgetpgrp
tcsendbreak
tcsetattr
tcsetpgrp
time
link
longjmp
lseek
mkdir
mkfifo
open
pause
sigemptyset
sigfillset
sigismember
signal
sigpending
sigprocmask
sleep
times
umask
uname
unlink
utime
wait
write
Ces primitives réentrantes sont :
661
✱
soit ininterruptibles (rapides, comme les E/S sur un disque),
✱
soit n’utilisent pas la mémoire du processus pour leur résultat.
662
Ensemble de signaux :
Ensemble de signaux
suite(1)
sigemptyset, sigfillset, sigaddset, sigdelset (3)
✱
✱
✱
Syntaxe :
#inlude <signal.h>
int sigemptyset (sigset_t* set );
int sigfillset (sigset_t* set );
int sigaddset (sigset_t* set, int signo );
int sigdelset (sigset_t* set, int signo );
Sémantique :
• sigemptyset / sigemptyset :
création d’un ensemble vide / plein.
• sigaddset / sigdelset :
ajout / retrait d’un signal à un ensemble.
• Si l’ensemble à construire contient peu de signaux,
on crée d’abord un ensemble vide, puis on lui ajoute
les signaux voulus, un par un.
Si l’ensemble contient beaucoup de signaux, on
crée un ensemble plein, puis on ôte ce qu’il faut.
Retour :
• 0, si OK,
• -1, si erreur
663
17. SIGNAUX
8.11 Primitives POSIX fiables
664
17. SIGNAUX
Ensemble de signaux :
8.11 Primitives POSIX fiables
Remarques sur les ensembles de signaux
sigismember (3)
✱
✱
✱
Syntaxe :
#inlude <signal.h>
int sigismember (onst sigset_t* set, int signo );
Retour :
• 1, si signo appartient à set,
• 0, sinon
Sémantique :
• teste l’appartenance de signo dans set.
✱
Les structures de type sigset_t doivent être déclarées
dans l’espace mémoire du processus.
✱
Leur réprésentation interne est inconnue :
type abstrait de donnée, TAD (en anglais ADT).
✱
Les quatre primitives fournies sont rustiques, mais réentrantes si elles portent sur des ensembles différents.
✱
On peut définir des fonctions de bibliothèque plus faciles
d’emploi (mais prendre garde à les laisser réentrantes).
665
17. SIGNAUX
8.11 Primitives POSIX fiables
666
17. SIGNAUX
8.11 Primitives POSIX fiables
sigaction (2)
Association d’un traitant à un signal :
suite(1)
sigaction (2)
✱
Syntaxe :
#inlude <signal.h>
int sigation ( int signo,
onst strut sigation * at,
strut sigation * oat );
strut sigation { /* spécification d’une action */
handler_t sa_handler; /* traitant */
✱
Retour : 0, si OK, -1, si erreur
✱
Sémantique :
• Associe le traitement sa_handler défini dans act au
signal signo.
• Si oact est non null, la structure pointée reçoit les
paramètres act du précédent appel de sigaction
pour signo.
/* ou SIG_IGN, SIG_DFL */
sigset_t sa_mask; /* signaux à masquer */
int sa_flags; /* options, cf. tableau suivant */
}
667
17. SIGNAUX
8.11 Primitives POSIX fiables
sigaction (2)
✱
668
17. SIGNAUX
8.11 Primitives POSIX fiables
Options de sigaction (2)
suite(2)
Sémantique (suite) :
• Les signaux dans act.sa_mask sont ajoutés au
masque du processus, avant l’appel au traitant.
• Le retour du traitant restaure le masque de signaux, d’avant l’entrée dans le traitant, donc démasque le signal associé.
• Le signal associé au traitant est implicitement
masqué dans act.sa_mask.
• L’association signal/traitant perdure jusqu’au prochain appel, contrairement à certaines versions de si-
SA_NOCLDSTOP Pour signo == SIGCHLD, ne pas générer ce
signal si un fils stoppe, seulement s’il se termine.
SA_NOCLDWAIT Pour signo == SIGCHLD, ne pas créer de
zombies avec les fils de l’appelant. Un appel à wait bloque alors le père jusqu’à ce
que tous ses fils se terminent avec CR ==
-1 et errno == ECHILD. (Utile si le père n’est
pas intéressé par les CR de ses fils)
SA_RESTART
Les appels système interrompus par ce signal sont automatiquement relancés.
SA_ON_STACK Si une pile auxiliaire a été déclarée par sigaltstack, utiliser cette pile.
gnal(3).
669
670
Options de sigaction
Signature d’un traitant handler_t
suite(1)
✱
SA_NODEFER
Ne pas masquer le signal à l’entrée de son
traitant, comme dans les vieilles versions de
signal(3).
SA_RESETHAND Ne pas maintenir l’association (signal, traitant) à l’entrée du traitant, comme dans les
vieilles versions de signal(3).
SA_SIGINFO
Fournir des informations supplémentaires
à l’entrée du traitant, dans une strut
siginfo (cf. ci-après).
Syntaxe (suite) :
typedef void (* handler_t )
( int, /* n◦du signal émis */
strut siginfo*, /* pour option SA_SIGINFO */
strut threadinfo* /* pour les threads */
) ;
671
17. SIGNAUX
8.11 Primitives POSIX fiables
672
17. SIGNAUX
8.11 Primitives POSIX fiables
Arguments d’un traitant : strut siginfo
Arguments d’un traitant : siginfo
suite(1)
✱
Syntaxe :
strut siginfo {
int si_signo; /* numéro du signal */
int si_errno; /* si 6= 0, valeur de errno */
int si_ode; /* info supplém., selon signal */
pid_t si_pid;/* pid du processus émetteur */
uid_t si_uid;/* RUID du processus émetteur */
... ;
/* autres champs... */
}
✱
Sémantique :
• Avec l’option SA_SIGINFO de sigaction vue précédemment, les traitants de signaux peuvent avoir
deux arguments supplémentaires :
⊲ un pointeur sur une strut siginfo qui donne
plus d’informations sur les conditions de déroutement ;
⊲ des informations sur les threads du processus
(non étudiés ici).
673
17. SIGNAUX
8.11 Primitives POSIX fiables
674
17. SIGNAUX
sigprocmask
Masquer, démasquer des signaux :
sigprocmask (2)
✱
✱
✱
8.11 Primitives POSIX fiables
Syntaxe :
#inlude <signal.h>
int sigpromask ( int how,
onst sigset_t* set,
sigset_t* oset );
suite(1)
Sémantique :
• sigprocmask modifie ou consulte le masque des signaux du
processus appelant (cf. page ??).
•
si set est non NULL, how indique comment affecter le masque
courant avec l’ensemble set :
SIG_BLOCK
set est l’ensemble de signaux supplémentaires à masquer.
SIG_UNBLOCK set est l’ensemble des signaux à démasquer
SIG_SETMASK set définit intégralement le nouveau
masque
Retour :
• 0, si OK,
• -1, si erreur
675
17. SIGNAUX
8.11 Primitives POSIX fiables
sigprocmask
✱
676
17. SIGNAUX
8.11 Primitives POSIX fiables
sigsetjmp (3)
suite(2)
Sémantique (suite) :
• si set est NULL, le masque du processus est inchangé. how est alors sans signification, mais oset
peut récupérer le masque en cours.
• si oset est non NULL, le système renvoie dans
la structure pointée la valeur du masque avant
l’affectation éventuelle.
677
✱
Syntaxe :
#inlude <setjmp.h>
int sigsetjmp (sigjmp_buf env, int savemask );
✱
Retour :
• 0, si définition d’un point de retour,
• 6= 0, si retour d’un siglongjmp (la valeur rendue est
celle émise dans val par siglongjmp)
✱
Sémantique :
• comme setjmp ( cf. setjmp, p. 285 ), avec sauvegarde du masque courant des signaux dans la
structure env.
678
siglongjmp (3)
sigsetjmp , siglongjmp (3)
✱
✱
Syntaxe :
#inlude <setjmp.h>
void siglongjmp (sigjmp_buf env, int val );
✱
Sémantique :
• comme longjmp ( cf. longjmp, p. 286 ), avec restauration du masque des signaux sauvegardé dans
env.
suite(1)
Sémantique :
• savemask indique :
⊲ (6= 0) s’il faut sauvegarder le masque,
⊲ (= 0) s’il ne faut pas le sauvegarder ; dans ce
cas, sigsetjmp est identique à setjmp.
• Ces deux primitives sont à utiliser de préférence à
leurs équivalents setjmp et longjmp dans les traitants de signaux, de manière à maîtriser le masque
de signaux à rétablir au point de retour.
679
17. SIGNAUX
8.11 Primitives POSIX fiables
680
17. SIGNAUX
Exemple d’utilisation de sigsetjmp ,
siglongjmp
8.11 Primitives POSIX fiables
Connaître les signaux en suspens :
sigpending (2)
✱
Syntaxe :
#inlude <signal.h>
int sigpending (sigset_t* set );
✱
Retour :
• 0, si OK,
• -1, si erreur
✱
Sémantique :
• retourne l’ensemble des signaux en suspens :
c’est-à-dire émis au processus, bloqués,
en attente d’être notifiés.
681
17. SIGNAUX
8.11 Primitives POSIX fiables
Exemple d’utilisation des primitives POSIX
682
17. SIGNAUX
8.11 Primitives POSIX fiables
Exemple d’utilisation des primitives POSIX
suite(1)
...
sigset_t nmask, omask, pmask;
sleep(5); /* SIGQUIT ii restera en suspens */
if (sigpending (&pmask) <0) ERR;
if (sigismember (&pmask, SIGQUIT))
printf("\nSIGQUIT est en suspens\n");
/* Initialisations */
if(signal (SIGQUIT, sig_quit) == SIG_ERR) ERR;
sigemptyset (&nmask);
sigaddset (&nmask, SIGQUIT);
/* Masquer SIGQUIT et sauvegarder le masque ourant */
if(sigpromask (SIG_BLOCK, &nmask, &omask)<0) ERR;
/* Restaurer le masque d'origine, e qui débloquera SIGQUIT */
if(sigpromask (SIG_SETMASK, &omask, NULL)<0) ERR;
printf("SIGQUIT débloqué\n");
sleep (5); /* SIGQUIT terminera ii ave un dump */
...
683
17. SIGNAUX
8.11 Primitives POSIX fiables
684
17. SIGNAUX
8.11 Primitives POSIX fiables
Exemple d’utilisation des primitives POSIX
Mise en attente fiable
suite(2)
avec masquage de signaux : sigsuspend (2)
stati void sig_quit(int signo){
printf("traitement de SIGQUIT\n"); /* non réentrant */
/* Reprise de l'assoiation par défaut */
if (signal (SIGQUIT, SIG_DFL)==SIG_ERR)
ERR;
return;
✱
Syntaxe :
#inlude <signal.h>
int sigsuspend ( onst sigset_t* set );
✱
Retour : pas de succès, -1, avec errno == EINTR
}
685
686
sigsuspend (2)
sigsuspend (2)
suite(1)
✱
✱
Sémantique :
• réalise de manière atomique (non interruptible) une attente et une définition du masque
suite(2)
lorsqu’un signal non masqué est émis, le système
interrompt l’appel sigsuspend et le traite comme
prévu :
• l’ignore ou
• le traite par défaut ( e.g. une terminaison),
• ou active un traitant dont le retour reprend juste
après l’appel sigsuspend interrompu, avec CR ==
-1 et errno == EINTR.
Le masque des signaux est restauré à sa valeur à
l’entrée de sigsuspend.
/* début opération atomique */
sigpromask (SIG_SETMASK, set, 0);
pause ();
/* fin opération atomique */
687
17. SIGNAUX
8.11 Primitives POSIX fiables
688
17. SIGNAUX
8.11 Primitives POSIX fiables
Section critique avec pause (2)
Exemple de section critique
suite(1)
avec attente non fiable avec pause
sigset_t nmask, omask ;
/* Initialisations */
if (signal(SIGINT, sig_int) == SIG_ERR) ERR;
sigemptyset (&nmask); sigaddset(&nmask, SIGINT);
/* Masquer SIGINT et sauvegarder le masque ourant */
if (sigpromask (SIG_BLOCK, &nmask, &omask)<0) ERR;
/* setion ritique protégée de SIGINT */
/* (on ne veut pas être interrompu par SIGINT) */
...
/* Fin de SC : libérer tous les signaux et attendre ave pause */
/* (on attend SIGINT) */
if (sigpromask (SIG_SETMASK, &omask, NULL)<0)
ERR;
/* A : oops ! il y a une fenêtre de temps ii... */
pause ();
/* ontinuer le traitement ... */
...
stati void sig_int (int signo) {
return; /* juste pour débloquer une attente... */
}
689
17. SIGNAUX
8.11 Primitives POSIX fiables
690
17. SIGNAUX
8.11 Primitives POSIX fiables
Section critique avec sigsuspend (2)
Exemple de section critique
suite(1)
avec attente fiable avec sigsuspend (2)
sigset_t nmask, omask, zmask;
/* Initialisations */
if (signal (SIGINT, sig_int) == SIG_ERR) ERR;
sigemptyset (&zmask);
sigemptyset (&nmask); sigaddset(&nmask, SIGINT);
/* A. masquer SIGINT et sauvegarder le masque ourant */
if (sigpromask (SIG_BLOCK, &nmask, &omask)<0) ERR;
/* Setion ritique protégée de SIGINT */
...
/* B. fin de SC : libérer et attendre un signal quelonque */
if (sigsuspend(&zmask) != -1) ERR;
/* C. retour du traitant via sigsuspend (appel systeme interrompu)
* le masque en B est restauré, donc SIGINT est bloqué
* => plus de fenêtre de temps !! (atomicité de sigsuspend)
* D. la restauration du masque en A débloque SIGINT */
if(sigpromask (SIG_SETMASK, &omask, NULL)<0) ERR;
/* E. ontinuer le traitement ... */
...
stati void sig_int(int signo){return;} /* débloque l'attente */
691
17. SIGNAUX
8.12 Exemples de synthèse
692
17. SIGNAUX
8.12 Exemples de synthèse
M. à j. d’une variable avec sigsuspend (2)
Mise à jour d’une variable globale
avec sigsuspend (2)
suite(1)
volatile int quitflag; /* mis à 1 par le traitant */
exemple(void){
sigset_t nmask, omask, zmask;
/* Intialisations */
if (signal (SIGINT, sig_int) == SIG_ERR) ERR;
if (signal (SIGQUIT, sig_int) == SIG_ERR) ERR;
sigemptyset (&zmask);
sigemptyset (&nmask); sigaddset (&nmask, SIGQUIT);
/* A. masquer SIGQUIT et sauvegarde le masque ourant */
if(sigpromask(SIG_BLOCK, &nmask, &omask)<0) ERR;
693
/* B. Attendre jusqu’à SIGQUIT (tous signaux débloqués)
* (n’importe quel signal débloque sigsuspend, d’où le while) */
while (quitflag == 0) sigsuspend (&zmask);
/* C. retour du traitant via sigsuspend (appel systeme interrompu)
* le masque en B est restauré, donc SIGQUIT est bloqué */
quitflag = 0; /* on peut don modifier quitflag ... */
/* D. la restauration du masque en A débloque SIGQUIT */
if(sigpromask (SIG_SETMASK, &omask, NULL)<0) ERR;
/* E. ontinuer le traitement ... */
/* ... */
}/* exemple */
694
Synchronisation avec des signaux
M-à-j d’une variable avec sigsuspend (2)
suite(2)
Nous avons vu (cf. chap. 4, page ??) plusieurs exemples de
synchronisation entre un processus père et son fils,
en utilisant 5 primitives :
stati void sig_int (int signo) {
/* traitant ommun SIGINT & SIGQUIT */
if (signo == SIGINT)
write (1, "\nSIGINT\n", 8);
else if (signo == SIGQUIT)
quitflag = 1; /* met à 1 pour boule prinipale */
return;
}
✱
INIT_SYNCHRO,
✱
WAIT_PARENT ,
✱
TELL_PARENT ,
✱
WAIT_CHILD,
✱
TELL_CHILD.
695
17. SIGNAUX
8.12 Exemples de synthèse
Synchronisation avec des signaux
696
17. SIGNAUX
8.12 Exemples de synthèse
Synchronisation avec des signaux
suite(1)
pid_t pid;
INIT_SYNCHRO ();
if ( (pid = fork ()) < 0) ERR;
else if (pid == 0) {/* - FILS - */
WAIT_PARENT (); /* attend le feu vert du père */
erit_ar_par_ar("message du fils\n");
} else { /* - PÈRE */
erit_ar_par_ar("message du père\n");
TELL_CHILD (pid); /* donne le feu vert au fils */
}
suite(2)
#define vert 0
#define rouge 1
/* Les variables globales sont dupliquées chez le père et le fils
* Il y a bien deux feux distincts qui sont utilisés... */
stati volatile int feu = rouge;
stati sigset_t nmask, omask, zmask;
/* Cette version utilise 2 signaux SIGUSR1 et SIGUSR2 :
* USR1: le père donne le feu vert au fils ;
* USR2: le fils donne le feu vert au père.
* remarque: en fait, un seul signal suffit ! */
697
17. SIGNAUX
8.12 Exemples de synthèse
Synchronisation avec des signaux
698
17. SIGNAUX
8.12 Exemples de synthèse
Synchronisation avec des signaux
suite(3)
suite(4)
void INIT_SYNCHRO (void) {
/* initialisation de la synhronisation (avant fork) */
sigemptyset (&zmask);
sigemptyset (&nmask); /* masque USR1 et USR2 */
sigaddset (&nmask, SIGUSR1);
sigaddset (&nmask, SIGUSR2);
stati void sig_usr ( int signo ) {
/* traitant commun pour SIGUSR1 et SIGUSR2
* mais qui agit sur deux feux distincts */
feu = vert;
return;
/* bloquer SIGUSR1, SIGUSR2, sauvegarder masque ourant */
if(sigpromask (SIG_BLOCK, &nmask, &omask)<0) ERR;
if(signal (SIGUSR1, sig_usr) == SIG_ERR) ERR;
if(signal (SIGUSR2, sig_usr) == SIG_ERR) ERR;
}
}
699
17. SIGNAUX
8.12 Exemples de synthèse
Synchronisation avec des signaux
700
17. SIGNAUX
8.12 Exemples de synthèse
Synchronisation avec des signaux
suite(5)
suite(6)
void WAIT_PARENT ( void ) {
/* attente du fils jusqu’au feu vert du père :
void TELL_CHILD ( pid_t pid ) {
/* donne le feu vert au fils */
kill (pid, SIGUSR1);
}
* le feu manipulé est celui du fils ! */
while (feu == rouge)
/* n'importe quel signal débloque sigsuspend, d'où le while */
sigsuspend (&zmask); /* démasque tous les signaux */
void TELL_PARENT ( pid_t pid ) {
/* donne le feu vert au père */
kill (pid, SIGUSR2);
}
/* Le feu est passé au vert. USR1 et USR2 sont encore bloqués
* (reprise de sigsuspend), donc sommes encore en section critique*/
feu = rouge; /* 'est le feu du fils */
/* remet le masque d'origine, e qui débloque USR1, USR2 */
if(sigpromask (SIG_SETMASK, &omask, NULL)<0) ERR;
}
701
702
Synchronisation avec des signaux
Implémentation fiable de sleep (3)
suite(7)
void WAIT_CHILD ( void ) {
(Version simplifiée qui ne préserve pas le temps
en cours dans le timer s’il est actif)
/* Attente du père jusqu’au feu vert du fils :
* code identique à WAIT_PARENT pour cette version...
stati void sig_alrm ( void ) {
/* rien à faire, juste débloquer une attente */
return;
}
* ... mais le feu manipulé est celui du père !
*/
WAIT_PARENT();
}
703
17. SIGNAUX
8.12 Exemples de synthèse
Implémentation fiable de sleep (3)
704
17. SIGNAUX
8.12 Exemples de synthèse
Implémentation fiable de sleep (3)
suite(1)
unsigned int sleep(unsigned int nses) {
strut sigation newat, oldat;
sigset_t newmask, oldmask, suspmask;
unsigned int unslept;
/* assoiation ALRM <-> sig_alrm, sans signaux bloqués */
newat.sa_handler = sig_alrm;
sigemptyset (&newat.sa_mask);
newat.sa_flags = 0;
sigation (SIGALRM, &newat, &oldat);
suite(2)
/* bloquer SIGALRM et sauvegarder masque ourant */
sigemptyset (&newmask);
sigaddset (&newmask, SIGALRM);
sigpromask (SIG_BLOCK, &newmask, &oldmask);
/* Armer le timer de nsec secondes :
* Cette version ne préserve pas l’activité éventuelle du timer ! */
alarm (nses);
705
17. SIGNAUX
8.12 Exemples de synthèse
Implémentation fiable de sleep (3)
706
17. SIGNAUX
8.12 Exemples de synthèse
Implémentation fiable de sleep (3)
suite(3)
suite(4)
/* Un signal quelconque ou SIGALRM a été traité
* SIGALRM est encore bloqué ;
* Restaurer les conditions initiales: timer, traitants, signaux. */
/* désative le timer s'il était enore atif */
unslept = alarm (0);
/* Traiter SIGALRM omme à l'entrée de sleep */
sigation (SIGALRM, &oldat, NULL);
/* masquer SIGALRM omme il était à l'entrée de sleep */
sigpromask (SIG_SETMASK, &oldmask, NULL);
return(unslept);
/* sigsuspend avec le masque d’origine et SIGALRM non bloqué.
* Ainsi soit SIGALRM, soit un autre signal débloquera l’attente */
suspmask = oldmask;
sigdelset (&suspmask, SIGALRM);
sigsuspend (&suspmask);
}
707
17. SIGNAUX
8.12 Exemples de synthèse
708
17. SIGNAUX
8.12 Exemples de synthèse
system (3) avec traitement des signaux
Implémentation fiable de system (3)
suite(1)
avec traitement des signaux
#inlude
#inlude
#inlude
#inlude
#inlude
int system (onst har* mdstring) {
/* Version omplète POSIX ave traitement des signaux */
pid_t pid;
int status;
strut sigation ignore, saveintr, savequit;
sigset_t hldmask, savemask;
<sys/types.h>
<sys/wait.h>
<errno.h>
<signal.h>
<unistd.h>
/* demande si un shell existe : toujours vrai ave Unix */
if (mdstring == NULL) return(1);
709
710
system (3) avec traitement des signaux
suite(2)
/* ignore SIGINT and SIGQUIT */
ignore.sa_handler = SIG_IGN;
sigemptyset(&ignore.sa_mask);
ignore.sa_flags = 0;
if(sigation (SIGINT, &ignore, &saveintr)<0) return(-1);
if(sigation (SIGQUIT, &ignore, &savequit)<0) return(-1);
/* bloquer SIGCHLD */
sigemptyset (&hldmask);
sigaddset (&hldmask, SIGCHLD);
if(sigpromask (SIG_BLOCK, &hldmask, &savemask)<0)
return(-1);
if ((pid = fork ())<0) { status = -1; }
system (3) avec traitement des signaux
else if (pid == 0) { /* - FILS */
/* restaurer traitements de signaux et masque d’origine
* SIGQUIT ou SIGINT termineront le shell
* La fin du shell enverra SIGCHLD au père, ce qui le débloquera. */
sigation(SIGINT, &saveintr, NULL);
sigation(SIGQUIT, &savequit, NULL);
sigpromask(SIG_SETMASK, &savemask, NULL);
/* exéuter un shell ave la ommande en argument */
exel ("/bin/sh", "sh", "-", mdstring, (har *) 0);
_exit (127); /* exe error */
}/* fin du fils */
711
17. SIGNAUX
8.12 Exemples de synthèse
system (3) avec traitement des signaux
suite(4)
else { /* PÈRE */
/* Attendre la fin du fils :
* SIGINT, SIGQUIT ignorés ;
* SIGCHLD débloquera l’attente. */
while (waitpid (pid, &status, 0) < 0)
if (errno != EINTR)
/* vraie erreur, pas une interruption de waitpid */
status = -1;
break;
suite(3)
712
17. SIGNAUX
8.12 Exemples de synthèse
system (3) avec traitement des signaux
suite(5)
/* Restauration des traitants et masques des signaux */
if(sigation (SIGINT, &saveintr, NULL)<0)
return(-1);
if(sigation (SIGQUIT, &savequit, NULL)<0)
return(-1);
if(sigpromask (SIG_SETMASK, &savemask, NULL)<0)
return(-1);
return(status);
}/* fin system */
}
713
714
Table des matières