Interruptions logicielles envoyées à un processus pour indiquer un événement exceptionnel
Exemples :
sys/signal.h
...
#define SIGHUP 1
#define SIGINT 2
#define SIGQUIT 3
#define SIGILL 4
#define SIGTRAP 5
#define SIGABRT 6
#define SIGPOLL 7
#define SIGIOT SIGABRT
#define SIGEMT 7
#define SIGFPE 8
#define SIGKILL 9
#define SIGBUS 10
...
$ man signal
No Name Default Action
1 SIGHUP terminate process
2 SIGINT terminate process
3 SIGQUIT create core image
4 SIGILL create core image
5 SIGTRAP create core image
6 SIGABRT create core image
7 SIGEMT create core image
8 SIGFPE create core image
9 SIGKILL terminate process
10 SIGBUS create core image
11 SIGSEGV create core image
12 SIGSYS create core image
13 SIGPIPE terminate process
14 SIGALRM terminate process
15 SIGTERM terminate process
16 SIGURG discard signal
17 SIGSTOP stop process
Nombre limité de signaux
Chaque signal a
SIG)Quelques signaux courants :
SIGHUP (1) Fermeture du terminal contrôlant le processus (hang up)SIGINT (2) Interruption (Ctrl-C)SIGQUIT (3) Quitter (Ctrl-\)SIGFPE (8) Exception lors d'une opération arithmétiqueSIGKILL (9) Termine le processus immédiatementSIGALRM (14) Signal d'horloge (utilisé pour les minuteries)SIGTERM (15) Demande au processus de terminerSIGSTOP et SIGTSTP (17, 18) Suspend l'exécution du processusSIGCONT (19) Reprend l'exécution du processusSIGCHLD (20) Changement de l'état d'un filsSIGUSR1 et SIGUSR2 (30, 31) À définir par l'utilisateurLa commande kill permet d'envoyer un signal à un processus
SIGTERM par défautOn peut aussi utiliser killall
Raccourcis clavier envoient un signal au processus au premier plan :
Ctrl-C envoie SIGTERMCtrl-Z envoie SIGTSTPCtrl-\ envoie SIGQUIT$ kill 1234
[1]+ Terminated: 15 ./a.out
$ kill -SIGSEGV 1234
Segmentation fault: 11
$ kill -9 1234
[1]+ Killed: 9 ./a.out
La commande kill -l liste les signaux disponibles
$ kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL
5) SIGTRAP 6) SIGABRT 7) SIGEMT 8) SIGFPE
9) SIGKILL 10) SIGBUS 11) SIGSEGV 12) SIGSYS
13) SIGPIPE 14) SIGALRM 15) SIGTERM 16) SIGURG
17) SIGSTOP 18) SIGTSTP 19) SIGCONT 20) SIGCHLD
21) SIGTTIN 22) SIGTTOU 23) SIGIO 24) SIGXCPU
25) SIGXFSZ 26) SIGVTALRM 27) SIGPROF 28) SIGWINCH
29) SIGINFO 30) SIGUSR1 31) SIGUSR2
L'état des signaux pour un processus est représenté par 2 entiers
Chaque bit représente un signal
Lorsque le processus est activé
struct sigaction {
void (* sa_handler) (int);
sigset_t sa_mask;
int sa_flags;
}
int sigaction(
int sig,
struct sigaction *act,
struct sigaction *old_act
);
void handle_sigint(int sig) {
printf("Reçu signal %d\n", sig);
}
int main() {
struct sigaction act;
act.sa_handler = handle_sigint;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGINT, &act, NULL);
while (1){}
}
$ ./a.out
^CReçu signal 2
^CReçu signal 2
void handler(int sig) { printf("Je suis occupé\n"); } int main() { struct sigaction act, old_act; act.sa_handler = handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGINT, &act, &old_act); printf("Je travaille\n"); sleep(5); sigaction(SIGINT, &old_act, NULL); printf("J'ai fini de travailler\n"); while(1){} }void handler(int sig) { printf("Je suis occupé\n"); } int main() { struct sigaction act; act.sa_handler = handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGINT, &act, NULL); printf("Je travaille\n"); sleep(5); act.sa_handler = SIG_DFL; sigaction(SIGINT, &act, NULL); printf("J'ai fini de travailler\n"); while(1){} }
Je travaille
^CJe suis occupé
J'ai fini de travailler
^C
Pour redéfinir le comportement d'un signal
voidsigaction() avec
typedef void (*sig_t) (int);
sig_t signal(int sig, sig_t func);
void handle_sigint(int sig) {
printf("Reçu signal %d\n", sig);
}
int main() {
signal(SIGINT, handle_sigint);
while (1){}
}
$ ./a.out
^CReçu signal 2
^CReçu signal 2
On peut aussi changer le handler avec signal()
sig : numéro du signalfunc : handlersignal est plus simple mais moins complète que sigaction
Parfois déconseillée pour raisons de compatibilité
void handler(int sig) {
printf("Reçu signal %d\n", sig);
}
int main() {
struct sigaction act, old_act;
act.sa_handler = handler;
act.sa_mask = 0;
act.sa_flags = 0;
sigaction(SIGINT, &act, NULL);
sigaction(SIGKILL, &act, NULL);
sigaction(SIGTERM, &act, NULL);
sigaction(SIGSTOP, &act, NULL);
sigaction(SIGTSTP, &act, NULL);
while(1){}
}
SIGKILL et SIGSTOP ne peuvent pas être ignorés ou redéfinis
$ ./a.out
Reçu signal 15 kill
^CReçu signal 2 Ctrl-C
^ZReçu signal 18 Ctrl-Z
kill -SIGSTOP
[1]+ Stopped ./a.out
$ fg
./a.out
Killed: 9 kill -SIGKILL
pid_t pid = getpid();
kill(pid, SIGINT); // ou raise(SIGINT);
int main() {
int stat;
pid_t pid = fork();
if (pid == 0) {
while(1){}
} else {
kill(pid, SIGINT);
wait(NULL);
}
}
pid_t pid;
void handler1(int sig) {
printf("ping\n"); kill(pid, SIGUSR1);
}
void handler2(int sig) {
printf("pong\n"); exit(0);
}
int main() {
struct sigaction act;
act.sa_handler = handler1;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGUSR1, &act, NULL);
if ((pid = fork()) == 0) {
act.sa_handler = handler2;
sigaction(SIGUSR1, &act, NULL);
kill(getppid(), SIGUSR1);
while(1){}
}
waitpid(pid, NULL, 0);
}
On peut envoyer des signaux avec
int kill(pid_t pid, int sig)
pid est le PID du processus ciblesig est le signal à envoyererrno)static void handler(int sig) { wait(NULL); } int main() { signal(SIGCHLD, handler); int pid = fork(); if (pid) { // père /* Tâche principale */ } else { // fils /* Tâche secondaire */ } }static void handler(int sig) { wait(NULL); } int main() { struct sigaction act; act.sa_handler = handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGCHLD, &act, NULL); int pid = fork(); if (pid) { // père /* Tâche principale */ } else { // fils /* Tâche secondaire */ } }int main() { signal(SIGCHLD, SIG_IGN); int pid = fork(); if (pid) { // père /* Tâche principale */ } else { // fils /* Tâche secondaire */ } }
Lorsqu'un fils termine, il envoie le signal SIGCHLD au parent
wait à ce momentSIGCHLD et le fils sera automatiquement retiré