Prise en compte des signaux en C

 

Les signaux sont mémorisés dans un tableau de la table des processus. On ne peut connaître le nombre d'occurrences d'un signal.

Les signaux sont éxaminés lors du passage du processus du mode noyau au mode utilisateur, ou lorsqu'il entre ou quitte un état endormi.

Un signal est traité lors du passage du mode noyau au mode utilisateur.

 

Un signal pourra être:

- Non traité par le processus.

- Intercepté par le processus.

- Intercepté et traité par le processus.

 

Les différentes valeurs des signaux

Voir annexes sur les signaux

 

Fonctions de gestion des signaux en C

#include <signal.h>

void (*signal(int typsig, void (*fonc)(int)))(int)

La fonction signal permet d'indiquer ce que doit faire le processus lors de la réception d'un signal.

typsig indique le signal concerné par la fonction.

fonc indique la mesure qui sera prise à reception du signal:

Si fonc = SIG_DFL

Le processus exécutera un exit sauf pour les signaux SIGCHLD (anciennement SIGCLD ) et SIGPWR.

Si fonc = SIG_IGN

Le processus ne tiendra pas compte du signal reçu. SIGKILL n'est pas influencé.

Pour SIGCHLD (anciennement SIGCLD) les processus fils ne laisseront pas de Zombie.

Si fonc = adresse d'une fonction.

la fonction fonc sera exécutée sur détection du signal correspondant, en paramêtre de cette fonction une donnée de type int passe le numéro de signal.

La fonction fonc est ensuite replacée à SIG_DFL sauf pour les signaux SIGKILL, SIGTRAP et SIGPWR. Pendant l'exécution de fonc pour SIGCHLD ( SIGCLD ), les signaux SIGCHLD ( SIGCLD ) sont perdus.

signal retourne l'ancienne valeur de fonc, sinon SIG_ERR si une erreur se produit.

#include <signal.h>

int kill ( int pid, int sig );

Cette fonction permet d'envoyer un signal à un processus ou à un ensemble de processus.

sig précise le signal à envoyé.

pid précise la destination du signal, un processus ou plusieurs.

pid>0

le signal est envoyé au processus du numéro pid.

pid=0

Le signal est envoyé à tous les processus (sauf 0 et 1) appartenant au même groupe que le processus émetteur.

pid=-1

Le signal est envoyé à tous les processus (sauf 0 et 1) dont le propriétaire réel est le propriétaire effectif de l'émetteur. (en mode Super utilisateur, tous les processus recoivent le signal,sauf 0 et 1)

pid<-1

Le signal est envoyé à tous les processus appartenant au groupe de processus identifié par " pid ".

Les deux fonctions présentées ci-dessus sont portables, dans le cadre du SYSTEM V version 4 de nouvelles fonctions plus souples gêrent les signaux.

int alarm (unsigned int t);

Cette fonction demande l'émission d'un signal SIGALRM vers le processus demandeur après t secondes.

Image non trouvée ! Ce signal est également utilisé par la fonction sleep(). Ne pas utiliser en même temps !

note:signal est paramétré pour relancer automatiquement les appels du système lents interrompus par l'arrivée d'un signal. Ce qui peut poser parfois des problèmes.

Exemple avec la commande accept pour les sockets. Le signal SIGINT ne pourra jamais interrompre votre programme tant que celui-ci est en attente dans accept, car relancé automatiquement. Pour palier ce problème, il sera nécessaire d'utiliser la commande sigaction()

#include <signal.h>

int sigaction(int signum, const struct sigaction *act,
struct sigaction *oldact);

La structure sigaction ressemblant à (dépendra des systèmes) :

struct sigaction {

void (*sa_handler) (int);
void (*sa_sigaction) (int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer) (void);

};

Dans tous les cas, oubliez sa_restorer. Non reconnu par POSIX

Pour sortir de accept() avec SIGINT, il faudra désactiver SA_RESTART, d'où le code suivant:

struct sigaction a;
a.sa_handler = fonc // fonction interceptant le signal
a.sa_flags = 0;
sigemptyset( &a.sa_mask );
sigaction( SIGINT, &a, NULL );

 

Fonctions d'attente des signaux en C

Ces fonctions permettent de placer le processus dans un état d'attente de signaux.

int pause ();

Le processus est suspendu jusqu'à réception d'un signal qui ne doit pas être ignoré.

Si le signal n'est pas intercepté le processus fait un exit.

Si le signal est traité par une fonction utilisateur, l'exécution du programme se poursuit après la fonction pause qui retourne -1 et errno = EINTR.

 

int wait (int *stat_1oc);

Le processus est suspendu jusqu'à ce que les processus fils se terminent ou jusqu'à l'arrêt d'un processus fils en cours de traçage s'arrête sur un point d'arrêt.

Le processus est activé sur réception d'une interruption, sur la détection d'un processus fils zombie ou si le processus n'a pas de fils.

Le contenu *stat_loc est:

n+128 Le processus fils est mort et est un zombie. Le signal n l'a tué.

256 * ( n % 256) Le processus fils est mort par un exit (n).

status, sur un mot de 16 bit, l'octet de poids faible est à zéro, l'octet de poids fort est la valeur de l'exit

256 * n + 127 Le processus fils est stoppé par le signal n.

status sera pour l'octet de poids faible : les 7 premiers bits sont = signal, le bit 8 = 1 pour core, 0 sinon.

 

Cas particulier pour status avec debug : octet fort = signal, octet faible = 0x7F (processus stoppé en debug (trace)).

Si le signal SIGCHLD ( anciennement SIGCLD) est ignoré, wait attendra la mort de tous les fils.

 

Il existe aussi une fonction waitpid() non étudié ici (du moins pour le moment !)

NoteIl existe aussi une variante à la commande wait: waitpid qui permet d'attendre le changement d'état d'un processus fils

pid_t waitpid(pid_t pid, int *status, int options);

Exemple:

waitpid(WAIT_ANY, NULL, WNOHANG);

Avec WAIT_ANY pour n'importe quel des processus fils

NULL pour ne pas récupérer le status ou une variable de type int

WNOHANG pour rendre la main immédiatement au processus père si aucun signal d'un fils présent. Il sera possible de mettre WUNTRACED pour un fils bloqué (et non suivi par ptrace) ou WCONTINUED si un fils bloqué a été relancé par SIGCONT

Exemple de programme en C

Ce programme va faire un fork. Le processus père enverra ensuite une dizaine de signaux SIGUSR1 par intervalle de temps de deux secondes vers le processus fils.

Le processus fils va intercepter ces signaux par la fonction fsig qui affichera un message à l'écran.

On est obligé de redéclarer la fonction fsig pour le signal SIGUSR1 dans cette même fonction, sinon après la réception du signal, un nouveau signal SIGUSR1 ne serait plus dérouté sur celle-ci.

Enfin, le père émet un signal SIGINT pour tuer le processus fils, et le programme père se termine par un exit.

Image non trouvée !