🕒 : 3 h maximum

Prérequis:

Langage C

But

  1. Comprendre les signaux et leurs gestionnaires.
  2. Utiliser alarm() pour des temporisations.
  3. Travailler avec sigaction pour une gestion robuste.

Répertoire du travail:

~/Works/TP_C_Signaux


Exercice 1_0 : Capture de SIGINT (Ctrl+C) avec signal

répertoire : ex1, code ex1.c

But : Empêcher Ctrl+C de terminer le programme.

#include <stdio.h>
#include <signal.h>
#include <unistd.h>

void handle_sigint(int sig) {
    /*  signal(SIGINT, handle_sigint); */ /* relance */
    printf("\nTu as appuyé sur Ctrl+C ! Mais je ne quitte pas.\n");
}

int main() {
    signal(SIGINT, handle_sigint);
    printf("Appuie sur Ctrl+C...\n");
    while (1) sleep(1);
    return 0;
}

Questions :

Que se passe-t-il si vous appuyez une fois puis plusieurs fois sur Ctrl+C ?

On va dé-commenter la ligne 6 , pour réarmer !

Que se passe-t-il si vous appuyez plusieurs fois sur Ctrl+C?

tester les commandes dans un autre terminal a coté de votre code lancé.

cours sur les processus sous linux

trouver un PID

pidof ex1 

autrement

ps -aux | grep ex1

on peut envoyer des signaux avec kill

kill -SIGINT PIDXXXX  # déterminer avant
#ou 
kill -2 PIDXXXX

Et tester le signal -SIGTERM ou -15

et tester le signal -SIGKILL ou -9

Exercice 1_1 sleep et pause

FonctionComportement
pause()Attend indéfiniment un signal. Ne retourne que lorsqu’un signal est reçu.
sleep(5)Attend 5 secondes max, mais peut être interrompu par un signal (retourne le temps restant).

répertoire ex1, code : ex1_1.c

#include <stdio.h>
#include <signal.h>
#include <unistd.h>

void handle_sigint(int sig) {
    printf("\nSignal SIGINT reçu (Ctrl+C) !\n");
}

int main() {
    signal(SIGINT, handle_sigint);
    printf("Appuyez sur Ctrl+C pendant sleep(5)...\n");

    int temps_restant = sleep(5);  // ← Remplacé pause() par sleep(5)
    
    if (temps_restant > 0) {
        printf("sleep() interrompu. Temps restant : %d sec\n", temps_restant);
    } else {
        printf("sleep() terminé naturellement.\n");
    }

    while (1);  // Pour garder le programme actif
    return 0;
}

Questions :

Tester avec sleep(5)

Tester en remplaçant sleep(5) par pause()

Donner les différence entre sleep(5) et pause()

Exercice 1_2 avec sigaction

répertoire ex1, code : ex1_2.c

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>

void handle_sigint(int sig) {
    const char *msg = "\nCtrl+C bloqué ! (Avec sigaction, c'est fiable)\n";
    write(STDOUT_FILENO, msg, strlen(msg));  // write() est async-safe
}

int main() {
    struct sigaction sa;
    memset(&sa, 0, sizeof(sa));
    sa.sa_handler = handle_sigint;
    sigemptyset(&sa.sa_mask);  // Aucun signal bloqué pendant l'exécution
    sa.sa_flags = SA_RESTART;  // Options : redémarre les appels système interrompus

    // Associer le gestionnaire à SIGINT
    if (sigaction(SIGINT, &sa, NULL) == -1) {
        perror("Erreur sigaction");
        return 1;
    }

    printf("Appuyez sur Ctrl+C... (PID: %d)\n", getpid());
    while (1) pause();
    return 0;
}

Question:

Comment en sortir?


Exercice 2 : Compteur avec alarm()

But : Utiliser alarm() pour afficher un message toutes les 2 secondes.

Répertoire : ex2 , code : alarm.c

#include <stdio.h>
#include <signal.h>
#include <unistd.h>

void handle_alarm(int sig) {
    printf("ALARME ! (2 secondes passées)\n");
    alarm(2);  // Reprogramme l'alarme
}

int main() {
    signal(SIGALRM, handle_alarm);
    alarm(2);  // Première alarme dans 2s
    printf("Compteur démarré (Ctrl+C pour quitter).\n");
    while (1) pause();  // Attend les signaux
    return 0;
}

Questions :

Que se passe-t-il si vous remplacez pause() par sleep(5) ?

Ajoutez un compteur global pour afficher le nombre d’alarmes déclenchées.


Exercice 3 : Blocage de signaux avec sigprocmask()

But : Bloquer temporairement SIGINT pendant une opération critique.

Répertoire : ex3 , code: sigprocmask.c

#include <stdio.h>
#include <signal.h>
#include <unistd.h>

void handle_sigint(int sig) {
    printf("SIGINT reçu, mais ignoré pendant le calcul.\n");
}

int main() {
    sigset_t mask;
    signal(SIGINT, handle_sigint);

    // Bloquer SIGINT
    sigemptyset(&mask);
    sigaddset(&mask, SIGINT);
    sigprocmask(SIG_BLOCK, &mask, NULL);

    printf("Calcul critique en cours (5s)...\n");
    sleep(5);

    // Débloquer SIGINT
    sigprocmask(SIG_UNBLOCK, &mask, NULL);
    printf("Calcul terminé. Ctrl+C fonctionne à nouveau.\n");

    while (1) pause();
    return 0;
}

Questions :

Testez en appuyant sur Ctrl+C pendant le sleep(5). Que se passe-t-il ?

Utilisez sigpending() pour afficher les signaux en attente.


Exercie 4 : signal SIGUSR1

Signaux SIGUSR1 et SIGUSR2 : Origine et Utilité

Les signaux SIGUSR1 (10) et SIGUSR2 (12) sont deux signaux définis par l’utilisateur dans les systèmes Unix/Linux. Contrairement aux signaux standards comme SIGINT (Ctrl+C) ou SIGKILL, ils n’ont aucun comportement prédéfini et sont entièrement customisables par le programmeur.

Répertoire: ex4 , code : sigusr1.c

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

// Variable globale pour contrôler la boucle principale
volatile sig_atomic_t stop = 0;

// Gestionnaire de signal
void handle_sigusr1(int sig) {
    if (sig == SIGUSR1) {
        printf("Signal SIGUSR1 reçu. Arrêt demandé.\n");
        stop = 1;  // On modifie le drapeau pour sortir de la boucle
    }
}

int main() {
    // Affiche le PID pour qu'on puisse envoyer le signal
    printf("Mon PID est : %d\n", getpid());
    printf("Envoyez 'kill -SIGUSR1 %d' depuis un autre terminal pour m'arrêter.\n", getpid());

    // Configuration du gestionnaire de signal
    signal(SIGUSR1, handle_sigusr1);

    // Boucle principale
    while (!stop) {
        printf("En attente... (Ctrl+C pour quitter immédiatement)\n");
        sleep(1);  // Réduit la consommation CPU
    }

    printf("Arrêt propre du programme.\n");
    return 0;
}

Questions :

Envoyez ‘kill -SIGINT PID’ depuis un autre terminal

Envoyez ‘kill -SIGUSR1 PID’ depuis un autre terminal

Donnez le code qui va utiliser le sigusr2 , code : sigusr2.c