Bien que cette question ait été répondue, permettez-moi de publier un flux détaillé des événements dans le noyau Linux.
Ceci est entièrement copié à partir des publications Linux: Linux Signals - Internals
sur le blog "Linux posts" à sklinuxblog.blogspot.in.
Programme Espace Utilisateur Signal C
Commençons par écrire un programme C de l'espace utilisateur de signal simple:
#include<signal.h>
#include<stdio.h>
/* Handler function */
void handler(int sig) {
printf("Receive signal: %u\n", sig);
};
int main(void) {
struct sigaction sig_a;
/* Initialize the signal handler structure */
sig_a.sa_handler = handler;
sigemptyset(&sig_a.sa_mask);
sig_a.sa_flags = 0;
/* Assign a new handler function to the SIGINT signal */
sigaction(SIGINT, &sig_a, NULL);
/* Block and wait until a signal arrives */
while (1) {
sigsuspend(&sig_a.sa_mask);
printf("loop\n");
}
return 0;
};
Ce code attribue un nouveau gestionnaire pour le signal SIGINT. SIGINT peut être envoyé au processus en cours en utilisant la combinaison de touches Ctrl+ C. Lorsque vous appuyez sur Ctrl+, Cle signal asynchrone SIGINT est envoyé à la tâche. Cela équivaut également à envoyer la kill -INT <pid>
commande dans un autre terminal.
Si vous faites un kill -l
(c'est un minuscule L
, qui signifie «liste»), vous connaîtrez les différents signaux qui peuvent être envoyés à un processus en cours.
[root@linux ~]# kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX
La combinaison de touches suivante peut également être utilisée pour envoyer des signaux particuliers:
- Ctrl+ C- envoie SIGINT quelle action par défaut est de mettre fin à l'application.
- Ctrl+ \ - envoie à SIGQUIT quelle action par défaut consiste à mettre fin au noyau de vidage de l'application.
- Ctrl+ Z- envoie SIGSTOP qui suspend le programme.
Si vous compilez et exécutez le programme C ci-dessus, vous obtiendrez la sortie suivante:
[root@linux signal]# ./a.out
Receive signal: 2
loop
Receive signal: 2
loop
^CReceive signal: 2
loop
Même avec Ctrl+ Cou kill -2 <pid>
le processus ne se terminera pas. Au lieu de cela, il exécutera le gestionnaire de signaux et reviendra.
Comment le signal est envoyé au processus
Si nous voyons les internes du signal envoyés à un processus et mettons Jprobe avec dump_stack à la __send_signal
fonction, nous verrons la trace d'appel suivante:
May 5 16:18:37 linux kernel: dump_stack+0x19/0x1b
May 5 16:18:37 linux kernel: my_handler+0x29/0x30 (probe)
May 5 16:18:37 linux kernel: complete_signal+0x205/0x250
May 5 16:18:37 linux kernel: __send_signal+0x194/0x4b0
May 5 16:18:37 linux kernel: send_signal+0x3e/0x80
May 5 16:18:37 linux kernel: do_send_sig_info+0x52/0xa0
May 5 16:18:37 linux kernel: group_send_sig_info+0x46/0x50
May 5 16:18:37 linux kernel: __kill_pgrp_info+0x4d/0x80
May 5 16:18:37 linux kernel: kill_pgrp+0x35/0x50
May 5 16:18:37 linux kernel: n_tty_receive_char+0x42b/0xe30
May 5 16:18:37 linux kernel: ? ftrace_ops_list_func+0x106/0x120
May 5 16:18:37 linux kernel: n_tty_receive_buf+0x1ac/0x470
May 5 16:18:37 linux kernel: flush_to_ldisc+0x109/0x160
May 5 16:18:37 linux kernel: process_one_work+0x17b/0x460
May 5 16:18:37 linux kernel: worker_thread+0x11b/0x400
May 5 16:18:37 linux kernel: rescuer_thread+0x400/0x400
May 5 16:18:37 linux kernel: kthread+0xcf/0xe0
May 5 16:18:37 linux kernel: kthread_create_on_node+0x140/0x140
May 5 16:18:37 linux kernel: ret_from_fork+0x7c/0xb0
May 5 16:18:37 linux kernel: ? kthread_create_on_node+0x140/0x140
La fonction principale appelle donc l'envoi du signal:
First shell send the Ctrl+C signal using n_tty_receive_char
n_tty_receive_char()
isig()
kill_pgrp()
__kill_pgrp_info()
group_send_sig_info() -- for each PID in group call this function
do_send_sig_info()
send_signal()
__send_signal() -- allocates a signal structure and add to task pending signals
complete_signal()
signal_wake_up()
signal_wake_up_state() -- sets TIF_SIGPENDING in the task_struct flags. Then it wake up the thread to which signal was delivered.
Maintenant, tout est mis en place et les modifications nécessaires sont apportées task_struct
au processus.
Traitement du signal
Le signal est vérifié / géré par un processus lorsqu'il revient d'un appel système ou si le retour d'une interruption est effectué. Le retour de l'appel système est présent dans le fichier entry_64.S
.
La fonction int_signal est appelée à partir de entry_64.S
laquelle la fonction est appelée do_notify_resume()
.
Vérifions la fonction do_notify_resume()
. Cette fonction vérifie si le TIF_SIGPENDING
drapeau est défini dans task_struct
:
/* deal with pending signal delivery */
if (thread_info_flags & _TIF_SIGPENDING)
do_signal(regs);
do_signal calls handle_signal to call the signal specific handler
Signals are actually run in user mode in function:
__setup_rt_frame -- this sets up the instruction pointer to handler: regs->ip = (unsigned long) ksig->ka.sa.sa_handler;
Appels et signaux SYSTEM
Les appels système «lents», par exemple bloquer la lecture / écriture, mettre les processus en attente:
TASK_INTERRUPTIBLE
ou TASK_UNINTERRUPTIBLE
.
Une tâche en état TASK_INTERRUPTIBLE
sera changée en TASK_RUNNING
état par un signal. TASK_RUNNING
signifie qu'un processus peut être planifié.
S'il est exécuté, son gestionnaire de signaux sera exécuté avant la fin de l'appel système «lent». Le syscall
ne se termine pas par défaut.
Si l' SA_RESTART
indicateur est défini, syscall
est redémarré une fois le gestionnaire de signaux terminé.
Les références