|Home|      <<Prev<<      <-Back--      >>Next>>

Fonctions de base d'Unix concernant les signaux


Tous les documents de cette page sont sous licence Creative Commons BY-NC-SA . Merci de la respecter.


©A. Dragut
Université Aix-Marseille
I.U.T.d'Aix en Provence - Département Informatique
Dernière mise à jour :18/10/2012




Rappel structure des répertoires

Sommaire du document


Liste des fonctions et concepts système étudiés

Dans cette série de dix exercices on explore les différentes manières de générer, recevoir et traiter les signaux, à l'aide des fonctions , kill(), sigaction(), sigsuspend(), select(). On étudie les traitements possibles lors de l'arrivée d'un signal.

Liste des exercices

Bon courage !



exo_01 liste des signaux, leur déroutement

Dans cet exercice

vous découvrez les trois traitements simples des signaux: Vous les testez avec des signaux clavier (Ctrl+touches) et avec kill du shell.

Quoi de neuf

Les noms des signaux se trouvent dans un tableau de NTCTS appelé _sys_siglist, déclaré dans /usr/include/signal.h. On peut également utiliser strsignal() , déclarée dans <string.h>.
On déroute un signal vers un traitant de signal Derout avec la fonction sigaction(). Cette fonction met en place une structure de type struct sigaction
struct sigaction {
    void     (* sa_handler)   (int);
    void     (* sa_sigaction) (int, siginfo_t *, void *);
    sigset_t    sa_mask;
    int         sa_flags;
    void     (* sa_restorer)  (void);
}
Les champs sa_handler et sa_sigaction ne s'utilisent pas simultanément. Les normes de programmation système POSIX disent que le champ sa_restorer est obsolète et ne doit pas etre utilisé.
Rappel de cours: un traitant de signal est de type sighandler_t et doit toujours prendre qu'un seul entier (le numéro du signal l'ayant fait appeler), et ne doit rien rendre.

Travail à faire


exo_02 restauration automatique du traitant par défaut

Dans cet exercice

Le but est d'apprendre à utiliser les drapeaux de la structure sigaction.

Quoi de neuf

La fonction sigaction() permet une manipulation très fine des aspects reliés à la réception des signaux. En occurence, la valeur SA_RESETHAND dans le champ sa_flags de la structure de type struct sigaction installée avec la fonction sigaction() demande la restauration automatique du traitant par défaut (en anglais le "reset handler").

Travail à faire

OPTIONNEL exo_03 restauration de l'action précédente; blocage pendant l'exécution du traitant

Dans cet exercice

On déroute SIGINT d'abord vers un traitant de signal, puis vers un autre, tout en bloquant des signaux pendant les exécutions des traitants. Les masques des signaux bloqués pendant les exécutions des traitants sont differents. À la fin, le programme restaure la première action, depuis la sauvegarde qu'il a bien faite.

Quoi de neuf

Lors de son appel, la fonction sigaction() fournit l'ancienne action qui était en place dans la zone pointée par son dernier paramètre. On peut ainsi la sauvegarder, pour une restauration ultérieure. On rappelle que bloquer un signal veut bien dire que le système note son arrivée, mais ne la dévoile au processus que lorsque le débloquage intervient.

Travail à faire

exo_04 -- exo_05 blocage des signaux pendant l'exécution du programme; section critique

Dans cet exercice

vous résolvez un problème d'interférence en bloquant le signal SIGINT avant d'entrer dans l'activité sensible et en le débloquant en sortant.

Quoi de neuf

On doit préparer une structure de type sigset_t pour pouvoir appeller Sigprocmask(). Cette structure est à manipuler avec les wrappers des fonctions: sigemptyset(), sigaddset(), sigdelset(), sigismember() La solution générale pour proteger une opération sensible est de la placer dans une section critique et de la protéger par un mécanisme dépendant du langage utilisé (verrous, sémaphores, moniteurs, objets protégés ou tâches). Dans le cas présent, le fait de bloquer le signal suffit. ou bien si on veut seulement rajouter notre blocage au traitement des signaux déjà mis en place par le MasquePrecedent.

Travail à faire

OPTIONNEL exo_06 attendre et noter l'arrivée d'un signal

Dans cet exercice

vous modifiez le programme de l'exercice précédent. Le nouveau traitant de signal enregistre l'occurrence des signaux, et c'est l'application qui décide du moment où elle veut les prendre en compte.

Quoi de neuf

La communication entre le traitant de signal et le reste du programme se fait au moyen d'une variable globale. Pour en assurer la cohérence, on a besoin d'un type spécial de variable, dont la valeur peut être accédée tout en ayant la garantie de ne jamais pouvoir être interrompus par un signal pendant l'accès. On utilisera le type sig_atomic_t . On a également besoin d'un qualifieur spécial qui empêche le compilateur d'optimiser trop -- volatile -- pour annoncer que la variable est susceptible d'être modifiée par un dispositif externe au programme (comme un traitant d'interruption ou de signal, etc.).
Enfin, on utilise aussi la fonction sigsuspend(const sigset_t *). Un appel sigsuspend(&Masque) fait, de manière atomique par rapport aux signaux, c.à.d ininterruptible par un signal, l'équivalent de :

Travail à faire



OPTIONNEL exo_07 SIGALRM et multiplexage des entrées/sorties avec select()

Dans cet exercice

vous écrivez un programme qui attend avec select() un événement clavier et qui l'affiche ensuite avec le temps écoulé. Si aucun événement clavier n'as pas lieu pendant un délai prefixé un signal SIGALRM sera renvoyé au programme.

Quoi de neuf

La fonction select() est appelée fonction de multiplexage d'entrées/sorties. Rappelons que les "fichiers" (au sens large d'Unix) peuvent être classés en deux catégories selon que la fonction système read() renvoie 0 lorsqu'ils sont vides (c'est le cas des fichiers disques "normaux") ou qu'elle bloque (normalement) le processus qui l'appelle lorsque le "fichier" est vide (c'est le cas du "fichier" clavier, des sockets, des pipes).
Rappelons aussi que la fonction select() est bloquante et donc le process l'appellant est endormi jusqu'à ce qu'au moins un événement attendu arrive, ou que le délai fixé en dernier paramètre arrive à expiration. Ce genre d'attente s'appelle une attente passive. Une description détailée des arguments et du comportement se trouve dans le cours.

Travail à faire


[1] On appelle builtin command du c-shell une commande intégrée au shell, qui est effectuée préférentiellement à une commande Unix de même nom. Par exemple, kill ou login sont à la fois des builtin commands du c-shell et des commandes Unix (de niveau 1).

Solutions

Solution exo_01


exo_01.cxx
Makefile
nsSysteme.cxx
CExc.h
INCLUDE_H
nsSysteme.h

Solution exo_02


exo_02.cxx
Makefile
nsSysteme.cxx
CExc.h
INCLUDE_H
nsSysteme.h

Solution exo_03


exo_03.cxx
Makefile
nsSysteme.cxx
CExc.h
INCLUDE_H
nsSysteme.h

Solution exo_04


exo_04.cxx
Makefile
nsSysteme.cxx
CExc.h
INCLUDE_H
nsSysteme.h

Solution exo_05


exo_05.cxx
Makefile
nsSysteme.cxx
CExc.h
INCLUDE_H
nsSysteme.h

Solution exo_06


exo_06.cxx
Makefile
nsSysteme.cxx
CExc.h
INCLUDE_H
nsSysteme.h

Solution exo_07


exo_07.cxx
Makefile
nsSysteme.cxx
CExc.h
INCLUDE_H
nsSysteme.h


|Home|      <<Prev<<      <-Back--      >>Next>>