Imprimer
Catégorie : R3.05 - Programmation système
Affichages : 8189

Signaux

Interception de signaux

Écrire un programme qui cherche à intercepter tous les signaux de 1 à (_NSIG - 1), puis se met en attente dans une boucle infinie. Pour chaque signal reçu, le programme devra afficher un message contenant le numéro du signal reçu.
Tester le programme en lui envoyant des signaux, soit avec la commande kill, soit via des raccourcis du terminal (Ctrl-C, Ctrl-\, Ctrl-Z, ...).
Vous écrirez quatre versions de votre programme :

  1. en utilisant la fonction signal(2) ou sigaction(2) ;
  2. en implémentant les deux sémantiques vues en cours (réarmement automatique ou non).

Synchronisation de processus

On souhaite afficher 10 lignes "IUT Belfort Montbéliard" à l'aide de 3 processus.  Pour cela, on crée 3 processus fils : Fils1, Fils2 et Fils3. Chaque processus se met en attente de récecption du signal SIGUSR1.

À réception du signal SIGUSR1 :

Le père commence par envoyer un signal SIGURS1 à Fils3. Lorsque le nombre de messages a été atteint, le père tue les processus fils et attend leur fin avant de se terminer lui-même.

Redirections (partie facultative)

Écrire un programme :

execute [-i entrée] [-o sortie] [-e erreur] [--] commande [args...]

qui exécute la commande passée en paramètre en redirigeant, lorsque les options sont spécifiées:

Vous écrirez deux versions de votre programme:

  1. une version utilisant les fonctions de haut-niveau (fopen(), freopen(), ...)
  2. une version utilisant les fonctions de bas niveau (open(), dup(), dup2(), ...)

NB:

Compléments sur les signaux

Description

Dans un processus, il est possible d'adopter trois comportements à la réception d'un signal :

Si un gestionnaire de signal est mis en place et que le signal en question est déclenché, deux modes de fonctionnement peuvent exister :

Mise en œuvre

Pour modifier le comportement, il est possible d'utiliser deux fonctions :

Exemples

Voici quelques exemples d'utilisation, pour le signal SIGUSR1. Soit la fonction suivante, utilisée comme gestionnaire

void machin(int sig) { printf("caught signal %d\n", sig); }

Avec signal

Synopsis
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
Usage
signal(SIGUSER1, SIG_DFL); // comportement par défaut

signal(SIGUSER1, SIG_IGN); // ou bien, ignorer le signal

signal(SIGUSER1, machin);  // ou bien, utilisation de machin()
Remarque

Par défaut sous Linux, avec les versions actuelles de la glibc, c'est le fonctionnement « à la BSD » qui est adopté. Pour sélectionner un fonctionnement « à la SysV » on peut ajouter, avant tout #include, la ligne :

#define _POSIX_C_SOURCE 200809L

Avec sigaction

Synopsis
#include <signal.h>
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
Usage
struct sigaction act;
act.sa_flags = 0;          // options, cf. manuel
sigemptyset(&act.sa_mask); // initialisation à l'ensemble vide

act.sa_handler = SIG_DFL; // comportement par défaut
act.sa_handler = SIG_IGN; // ou bien, ignorer le signal
act.sa_handler = machin;  // ou bien, utilisation de machin()

sigaction(SIGUSR1, &act, NULL);