Meskipun pertanyaan ini telah dijawab, izinkan saya memposting alur acara yang terperinci dalam kernel Linux.
Ini sepenuhnya disalin dari posting Linux: Linux Signals - Internal
di blog "Linux posts" di sklinuxblog.blogspot.in.
Program Ruang Pengguna Sinyal C
Mari kita mulai dengan menulis program ruang C pengguna sinyal sederhana:
#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;
};
Kode ini memberikan penangan baru untuk sinyal SIGINT. SIGINT dapat dikirim ke proses yang berjalan menggunakan kombinasi tombol Ctrl+ C. Ketika Ctrl+ Cditekan maka sinyal asinkron SIGINT dikirim ke tugas. Ini juga setara dengan mengirim kill -INT <pid>
perintah di terminal lain.
Jika Anda melakukan kill -l
(itu huruf kecil L
, yang berarti "daftar"), Anda akan mengetahui berbagai sinyal yang dapat dikirim ke proses yang sedang berjalan.
[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
Juga kombinasi tombol berikut dapat digunakan untuk mengirim sinyal tertentu:
- Ctrl+ C- mengirimkan SIGINT tindakan default mana yang akan menghentikan aplikasi.
- Ctrl+ \ - mengirimkan SIGQUIT yang merupakan tindakan default untuk menghentikan inti dumping aplikasi.
- Ctrl+ Z- mengirimkan SIGSTOP yang menghentikan program.
Jika Anda mengkompilasi dan menjalankan program C di atas maka Anda akan mendapatkan output berikut:
[root@linux signal]# ./a.out
Receive signal: 2
loop
Receive signal: 2
loop
^CReceive signal: 2
loop
Bahkan dengan Ctrl+ Catau kill -2 <pid>
proses tidak akan berakhir. Sebaliknya itu akan menjalankan penangan sinyal dan kembali.
Bagaimana sinyal dikirim ke proses
Jika kita melihat internal pengiriman sinyal ke suatu proses dan menempatkan Jprobe dengan dump_stack di __send_signal
fungsi kita akan melihat jejak panggilan berikut:
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
Jadi fungsi utama panggilan untuk mengirim sinyal seperti:
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.
Sekarang semuanya sudah diatur dan perubahan yang diperlukan dilakukan untuk task_struct
proses.
Penanganan sinyal
Sinyal diperiksa / ditangani oleh suatu proses ketika kembali dari panggilan sistem atau jika kembali dari interupsi dilakukan. Pengembalian dari panggilan sistem hadir dalam file entry_64.S
.
Fungsi int_signal function dipanggil dari entry_64.S
mana memanggil fungsi do_notify_resume()
.
Mari kita periksa fungsinya do_notify_resume()
. Fungsi ini memeriksa apakah kita TIF_SIGPENDING
menetapkan flag di 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;
Panggilan dan sinyal SISTEM
Syscalls "Lambat" misalnya memblokir baca / tulis, menempatkan proses ke status menunggu:
TASK_INTERRUPTIBLE
atau TASK_UNINTERRUPTIBLE
.
Tugas dalam status TASK_INTERRUPTIBLE
akan diubah ke TASK_RUNNING
status oleh sinyal. TASK_RUNNING
berarti suatu proses dapat dijadwalkan.
Jika dijalankan, penangan sinyalnya akan dijalankan sebelum penyelesaian syscall "lambat". Tidak syscall
lengkap secara default.
Jika SA_RESTART
flag diatur, syscall
dihidupkan ulang setelah penangan sinyal selesai.
Referensi