TP6 - Signaux
Le but de ce TP est d'envoyer des signaux
Exercice 0 - Instructions
Il y a un fichier à rendre pour chaque exercice.
- Exercice 1 : 3 points
- Exercice 2 : 3 points
- Exercice 3 : 3 points
Exercice 1
Nom du fichier : votrelogin_ctrlc.c
On va faire un petit programme qui affiche un compteur toutes les secondes : 1, 2, 3, 4...
-
On peut déjà implémenter ce programme.
-
Implémenter maintenant un
handler
qui va récupérer le Ctrl-C du terminal et afficher la phrase suivante :
Tu as essayé de m'envoyer dormir X fois. Au bout de 5 fois, j'accepterai d'aller dormir.
X
doit bien sûr être remplacé par le nombre de fois où le signal a été reçu.
On pourra utiliser une variable globale.
Le programme doit quitter après avoir affiché :
Tu as essayé de m'envoyer dormir 5 fois : je vais au dodo !
- Pendant que votre programme est en cours d'exécution, essayer dans un nouveau terminal de tuer le programme avec les commandes
kill
etpkill
, en utilisant tour à tour les signauxSIGINT
etSIGTERM
. Quelles sont les 4 commandes à taper ? Quelles différences constate-t-on entre les deux signaux ? Répondre dans un commentaire dans le fichier C.
Rappels du cours : gérer un signal en C
Quand on tape Ctrl-C, le signal SIGINT
est envoyé au processus.
Par défaut, ce signal termine le programme, mais on peut changer ce comportement.
On va utiliser la fonction standard vue en cours :
#include <signal.h>
int sigaction(int signum,
const struct sigaction *new_action,
struct sigaction *old_action);
- Le premier argument est le signal à intercepter (les constantes
SIGINT
, etc sont également définies danssignal.h
) - Le second argument, optionel, est une structure
sigaction
qui va contenir le nom d'une fonction à exécuter quand on reçoit le signal. Si on veut qu'il n'y pas dehandler
pour ce signal, on peut mettreNULL
. - Le troisième argument, optionel, sert à obtenir l'éventuelle fonction du
précédent
handler
pour ce signal. Si on ne veut pas récupérer cette information, on peut mettreNULL
. - Manuel :
man sigaction
- Exemple d'utilisation
Si je trouve encore quelqu'un qui essaie de coder une fonction standard, je m'énerve 💢
Une fonction standard est une fonction qui existe déjà, je ne vous demande pas de la recoder, mais de l'utiliser !
La page du manuel man 7 signal
présente en détail le fonctionnement des signaux.
Rappels du cours : envoyer un signal en Shell
$ kill <PID> # default signal: SIGTERM
$ kill -SIGKILL <PID>
$ kill -SIGUSR1 <PID>
$ ...
$ pgrep <NAME>
$ pkill <NAME> # default signal: SIGTERM
$ pkill -SIGUSR1 <NAME>
$ ...
Voir les PID de tous les processus en cours d'exécution :
$ ps -e
Démo
Exercice 2
Nom du fichier : votrelogin_sigchild.c
Petites révisions : on va créer un thread et un processus 👀
N'hésitez pas à aller regarder les TPs précédents et leurs corrections !
Notre programme va créer un processus fils.
- Le processus fils :
- Crée un handler pour le signal
SIGTERM
. Quand on reçoit ce signal, on affiche un message et on quitte le processus. - Son main thread affiche un compteur de secondes, comme l'exercice précédent.
- Crée un handler pour le signal
- Le processus parent :
- Crée un thread qui envoie à l'enfant un SIGSTOP, un SIGCONT, un SIGTERM. En attendant quelques secondes entre chaque signal.
- Le main thread attend juste la fin de l'exécution du fils et quitte.
Rappels du cours : envoyer un signal en C
On va utiliser la fonction standard vue en cours :
#include <signal.h>
int kill(pid_t pid, int signal);
- Le premier argument est le processus auquel envoyer un signal. 0 pour soi-même.
- Le second argument est le signal à envoyer
La fonction kill porte mal son nom : elle ne permet pas que de tuer des processus, mais aussi d'envoyer un signal.
Démo
Exercice 3
Nom du fichier : votrelogin_cars_stop.c
Maintenant que vous savez gérer un signal comme des pros, on va appliquer ça à nos petites voitures.
Reprendre la version de son choix d'un TP précédent. On pourra récupérer sa propre version, ou une correction. Je conseille quand même de prendre une version assez avancée, c'est plus satisfaisant que de repartir d'une version minimale.
On va ajouter une fonction gestionnaire du signal SIGTSTP
, qui est reçu quand Ctrl-Z est pressé.
Lorsque Ctrl-Z est pressé, on devra :
- Effacer l'écran et restaurer l'ancien mode du terminal. On a déjà une fonction qui fait ça
- S'envoyer à soi-même un SIGSTOP. Le processus va donc se mettre en pause.
La suite, à écrire à la suite dans notre fonction, s'exécutera quand on tapera fg
dans le terminal, ce qui aura comme effet de reprendre l'exécution du processus :
- Restaurer l'écran et changer le mode du terminal. On a déjà une fonction qui fait ça, il suffit de l'appeler. Attention à ne pas initialiser deux fois un mutex ou un sémaphore, c'est interdit !