Sebbene questa domanda abbia avuto una risposta, lasciatemi pubblicare un flusso dettagliato di eventi nel kernel Linux.
Questo è copiato interamente dai post di Linux: Segnali Linux - Internals
nel blog "Post di Linux" su sklinuxblog.blogspot.in.
Programma Spazio utente segnale C
Cominciamo con la scrittura di un semplice programma C di spazio utente del segnale:
#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;
};
Questo codice assegna un nuovo gestore per il segnale SIGINT. SIGINT può essere inviato al processo in esecuzione utilizzando la combinazione di tasti Ctrl+ C. Quando Ctrl+ Cviene premuto, il segnale asincrono SIGINT viene inviato all'attività. È anche equivalente all'invio del kill -INT <pid>
comando in un altro terminale.
Se fai un kill -l
(che è una minuscola L
, che sta per "elenco"), arriverai a conoscere i vari segnali che possono essere inviati a un processo in esecuzione.
[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
Inoltre, è possibile utilizzare la seguente combinazione di tasti per inviare segnali particolari:
- Ctrl+ C- invia a SIGINT quale azione predefinita è terminare l'applicazione.
- Ctrl+ \ - invia a SIGQUIT quale azione predefinita è terminare il core di dumping dell'applicazione.
- Ctrl+ Z- invia SIGSTOP che sospende il programma.
Se compili ed esegui il programma C sopra, otterrai il seguente output:
[root@linux signal]# ./a.out
Receive signal: 2
loop
Receive signal: 2
loop
^CReceive signal: 2
loop
Anche con Ctrl+ Co kill -2 <pid>
il processo non verrà terminato. Invece eseguirà il gestore del segnale e ritornerà.
Come viene inviato il segnale al processo
Se vediamo l'internals del segnale che invia a un processo e mettiamo Jprobe con dump_stack alla __send_signal
funzione vedremo la seguente traccia di chiamata:
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
Quindi la funzione principale richiede l'invio del segnale è come:
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.
Ora tutto è impostato e vengono apportate le modifiche necessarie task_struct
al processo.
Gestione del segnale
Il segnale viene controllato / gestito da un processo quando ritorna dalla chiamata di sistema o se viene eseguito il ritorno dall'interruzione. Il ritorno dalla chiamata di sistema è presente nel file entry_64.S
.
Viene chiamata la funzione int_signal da entry_64.S
cui chiama la funzione do_notify_resume()
.
Controlliamo la funzione do_notify_resume()
. Questa funzione controlla se il TIF_SIGPENDING
flag è impostato in 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;
Chiamate e segnali di SISTEMA
Syscall "lenti", ad es. Blocco della lettura / scrittura, messa in attesa dei processi:
TASK_INTERRUPTIBLE
o TASK_UNINTERRUPTIBLE
.
Un'attività nello stato TASK_INTERRUPTIBLE
verrà cambiata nello TASK_RUNNING
stato da un segnale. TASK_RUNNING
significa che è possibile pianificare un processo.
Se eseguito, il suo gestore di segnale verrà eseguito prima del completamento della scalinata "lenta". Il syscall
non si completa per impostazione predefinita.
Se SA_RESTART
flag impostato, syscall
viene riavviato al termine del gestore del segnale.
Riferimenti