diff --git a/content/progsys/4_les-signaux/files/presentation.pdf b/content/progsys/4_les-signaux/files/presentation.pdf new file mode 100644 index 0000000..37f2437 Binary files /dev/null and b/content/progsys/4_les-signaux/files/presentation.pdf differ diff --git a/content/progsys/4_les-signaux/index.md b/content/progsys/4_les-signaux/index.md new file mode 100644 index 0000000..ac50192 --- /dev/null +++ b/content/progsys/4_les-signaux/index.md @@ -0,0 +1,242 @@ +--- +title: "Les signaux" +categories: ["Programmation système", "cours"] +tags: ["C", "programmation", "signaux"] +date: 2018-09-25 +--- + +En programmation système, un signal est une notification à un processus qu'un +évènement a eu lieu. Également appelés **Interruptions Logicielles**, les +signaux son asynchrone est il est impossible de prédire à quel moment il +arriveront. + +Les signaux couvrent plusieurs types d'évènements : + + * **Les actions utilisateurs** `CTRL + C` pour *SIGINT* ou `CRTL + Z` pour + *SIGSTOP* + * **Les fautes matérielles** comme la division par zéro *SIGFPE*, la référence + mémoire invalide *SIGSEGV*, écriture mémoire erronée *SIGSEGV* etc. + * **les fautes logicielles** comme l'erreur d'écriture dans un tube *SIGPIPE*, + la notification urgente de données disponibles *SIGURG*, l'alarme *SIGALRM* + +Ils représentent une forme basique de communication inter-processus ( *IPC* ) +mais permettent aussi à l'utilisateur d'intervenir dans le déroulement d'un +processus. (voir `man 1 kill` et `man 2 kill`). + +C'est au processus de se déclarer à l'écoute d'un type d'évènement en +initialisant un gestionnaire appelé lorsque l'évènement visé aura lieu. Lorsque +ce dernier a lieu, le gestionnaire est appelé avec toutes les informations +nécessaires. A la fin de l'exécution du gestionnaire, l'exécution du processus +reprend normalement à l'endroit ou elle s'est arrêtée. + +## Comportement associés aux signaux. + +Par défaut, des comportements sont associés aux signaux : + + * **stop** : arrête le processus + * **cont** : continuer le processus s'il est arrêté. + * **term** : terminer le processus + * **ign** : ignorer le processus + * **core** : créer un fichier *core* (contexte d'exécution du processus) puis + *sigterm* + +## Liste des signaux + +### Norme POSIX 1-1999 + +Signal | Valeur | Action | Commentaire +--------|--------|--------|---------------------------------------------------- +SIGHUP | 1 | Term | Déconnexion du terminal ou fin du processus de contrôle +SIGINT | 2 | Term | Interruption depuis le clavier `CTRL + C` +SIGQUIT | 3 | Core | Demande ”Quitter” depuis le clavier `CTRL + \\` +SIGILL | 4 | Core | Instruction illégale +SIGABRT | 6 | Core | Signal d’arrêt depuis abort(3) +SIGFPE | 8 | Core | Erreur mathématique virgule flottante +SIGKILL | 9 | Term | Signal ”KILL” +SIGSEGV | 11 | Core | Référence mémoire invalide +SIGPIPE | 13 | Term | Écriture dans un tube sans lecteur +SIGALRM | 14 | Term | Temporisation alarm(2) écoulée +SIGTERM | 15 | Term | Signal de fin +SIGUSR1 | 10 | Term | Signal utilisateur 1 +SIGUSR2 | 12 | Term | Signal utilisateur 2 +SIGCHLD | 17 | Ign | Fils arrêté ou terminé +SIGCONT | 18 | Cont | Continuer si arrêté +SIGSTOP | 19 | Stop | Arrêt du processus +SIGTSTP | 20 | Stop | Stop invoqué depuis le terminal `CTRL + Z` +SIGTTIN | 21 | Stop | Lecture sur le terminal en arrière-plan +SIGTTOU | 22 | Stop | Écriture dans le terminal en arrière-plan + +Les signaux **SIGKILL** et **SIGSTOP** ne peuvent ni être capturés ou ignorés. + + +### Normes SUSv2 et POSIX 1-2001 + +Signal | Valeur | Action | Commentaire +----------|--------|--------|-------------------------------------------------- +SIGBUS | 7 | Core | Erreur de bus (mauvais accès mémoire) +SIGPOLL | | Term | Événement ”pollable”, synonyme de SIGIO +SIGPROF | 27 | Term | Expiration de la temporisation pour le suivi +SIGSYS | 31 | Core | Mauvais argument de fonction +SIGTRAP | 5 | Core | Point d’arrêt rencontré +SIGURG | 23 | Ign | Condition urgente sur socket +SIGVTALRM | 26 | Term | Alarme virtuelle +SIGXCPU | 24 | Core | Limite de temps CPU dépassée +SIGXFSZ | 25 | Core | Taille de fichier excessive +SIGWINCH | 28 | Ign | Fenêtre redimensionnée + +## Le core dump + +Un **core dump** est une image mémoire d'un processus prise au moment d'un +plantage. Elle contient des information utiles pour l'analyse du crash : + + * copie de la mémoire au moment du plantage + * statut de terminaison du processus + * copie des registres *CPU* + +Prenons l'exemple de code suivant : + +```C +int main () +{ + int a = 10; + int b = 0; + a = a / b +} +``` + +Compilons le et exécutons le : + +```shell +$ gcc -g -Wall sigfpe.c -o sigfpe +$ ./sigfpe +[2] 8112 floating point exception (core dumped) ./sigfpe +``` + +Analysons maintenant le *core dump* avec `gdb` + +```shell +$ gdb sigfpe core +GNU gdb (Debian 7.11.1-2) 7.11.1 +Core was generated by `./sigfpe'. +Program terminated with signal SIGFPE, Arithmetic exception. +#0 0x00000000004004ec in main () at sigfpe.c:4 +4 a = a / b; +(gdb) backtrace full +#0 0x00000000004004ec in main () at sigfpe.c:4 + a = 10 + b = 0 +(gdb) +``` + +## Gestion des signaux. + +en programmation système, la gestion des signaux revient à changer le +comportement par défaut par un souhaité lors de la réception d'un signal donné +par un processus. + +```C +#include + +typedef void (*sighandler_t)(int); +sighandler_t signal(int signum, sighandler_t handler); +``` + + * `signum` est le numéro de signal à modifier + * `handler` vaut soit *SIG_IGN* pour ignorer le signal, soit *SIG_DFL* pour le + réinitialiser à sa valeur par défaut ou est un pointeur vers une fonction à + appeler. + +L'appel à `signal()` renvoie la valeur du gestionnaire de signal précédent en +cas de réussite, sinon *SIG_ERR*. + +### exemple de code + +```C +#include +#include +#include +#include + +void sigusr1_trigger() { + write(1, "SIGUSR1 received\n", 17); +} + +int main () { + if (signal(SIGUSR1, sigusr1_trigger) == SIG_ERR) { + perror("Unable to catch SIGUSR1\n"); + } + else { + printf("SIGUSR1 is catched on process with PID=%d\n", getpid()); + } + for(;;) { + sleep(10); + } +} +``` + +#### Exécution + +##### 1 sur le premier terminal + +```shell +$ ./sigusr1 +SIGUSR1 is catched on process with PID=10333 +``` + +##### 2 Sur le second terminal, envoi du signal : + +```shell +$ kill -USR1 10333` +``` + +##### 3 Retour sur le premier terminal : + +```shell +$ ./sigusr1 +SIGUSR1 is catched on process with PID=10333 +SIGUSR1 received +``` + +## Envoyer des signaux + +Des signaux peuvent être envoyés à d'autres processus avec `kill()` ou au +processus en cours avec `raise()`. + +```C +include + +int kill(pid_t pid, int sig); +int raise(int sig); +``` + +Ces deux fonctions renvoient 0 en cas de succès, sinon -1. + +Il est aussi possible de bloquer le processus courant et d'attendre un signal +avec la fonction `pause()` + +```C +int pause(void); +``` + +En cas d'erreur, retourne -1 avec errno positionné à *EINTR* + +## Poser une alarme + +Un processus peut définir une alarme qui aboutira à l'envoi d'un signal +*SIGALRM* au bout d'un temps défini. Il n'est cependant possible de ne définir +qu'une seule alarme par processus. + +```C +#include + +unsigned int alarm(unsigned int seconds); +``` + +Il est aussi possible d'annuler une alarme précédemment définir avec +`alarm(0)`. + +### Bibliographie + +[Présentation][f_pres] support de cours + +[f_pres]:files/presentation.pdf