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

Nom du fichier : votrelogin_ctrlc.c

On va faire un petit programme qui affiche un compteur toutes les secondes : 1, 2, 3, 4...

  1. On peut déjà implémenter ce programme.

  2. 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 !

  1. Pendant que votre programme est en cours d'exécution, essayer dans un nouveau terminal de tuer le programme avec les commandes kill et pkill, en utilisant tour à tour les signaux SIGINT et SIGTERM. 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 dans signal.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 de handler pour ce signal, on peut mettre NULL.
  • 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 mettre NULL.
  • 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.


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 :

  1. Effacer l'écran et restaurer l'ancien mode du terminal. On a déjà une fonction qui fait ça
  2. 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 :

  1. 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 !

Démo