Her ne kadar bu soru cevaplansa da, Linux çekirdeğinde ayrıntılı bir olay akışı göndermeme izin verin.
Bu tamamen Linux yayınlarından kopyalanır : Linux İşaretleri - İnternetteki
“Linux yayınları” blogunda sklinuxblog.blogspot.in.
Sinyal Kullanıcı Alanı C Programı
Basit bir işaret kullanıcı alanı C programı yazmaya başlayalım:
#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;
};
Bu kod, SIGINT sinyali için yeni bir işleyici atar. SIGINT, Ctrl+ Ctuş kombinasyonunu kullanarak çalışan prosese gönderilebilir . Ne zaman Ctrl+ Co zaman basıldığında asenkron sinyal SIGINT göreve gönderilir. kill -INT <pid>
Komutun başka bir terminale gönderilmesine de eşdeğerdir .
Bir yaparsanız kill -l
(bu L
, “liste” anlamına gelen bir küçük harf) , çalışan bir sürece gönderilen çeşitli sinyalleri öğreneceksiniz.
[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
Ayrıca, belirli sinyalleri göndermek için aşağıdaki tuş kombinasyonunu kullanabilirsiniz:
- Ctrl+ C- SIGINT'i hangi varsayılan eylemin uygulamayı sonlandırması gerektiğini gönderir.
- Ctrl+ \ - SIGQUIT'e hangi varsayılan eylemin uygulama boşaltma çekirdeğini sonlandırmak olduğunu gönderir.
- Ctrl+ Z- programı askıya alan SIGSTOP'u gönderir.
Yukarıdaki C programını derler ve çalıştırırsanız aşağıdaki çıktıları alırsınız:
[root@linux signal]# ./a.out
Receive signal: 2
loop
Receive signal: 2
loop
^CReceive signal: 2
loop
Hatta ile Ctrl+ Cveya kill -2 <pid>
sürecin sona olmayacaktır. Bunun yerine sinyal işleyicisini yürütecek ve geri dönecektir.
Sinyal işleme nasıl gönderilir?
Sinyalin içselini bir işleme gönderir ve __send_signal
fonksiyona dump_stack ile Jprobe koyarsak aşağıdaki çağrı izini görürüz:
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
Yani ana fonksiyon sinyali göndermeyi gerektirir:
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.
Şimdi her şey ayarlandı ve task_struct
süreç için gerekli değişiklikler yapıldı .
Sinyalin kullanımı
Sinyal, sistem çağrısından döndüğünde veya kesmeden dönüş yapıldığında bir işlem tarafından kontrol edilir / kullanılır. Sistem çağrısından dönüş dosyada var entry_64.S
.
İşlev int_signal fonksiyonu denir entry_64.S
olan işlevini çağırır do_notify_resume()
.
İşlevi kontrol edelim do_notify_resume()
. Bu işlev şurada belirtilen TIF_SIGPENDING
bayrağın olup olmadığını kontrol eder 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;
SYSTEM çağrıları ve sinyalleri
“Yavaş” sistemler, örneğin okuma / yazma engelleme, işlemleri bekleme durumuna alma:
TASK_INTERRUPTIBLE
veya TASK_UNINTERRUPTIBLE
.
Durumdaki bir görev, bir sinyal ile duruma TASK_INTERRUPTIBLE
değiştirilecektir TASK_RUNNING
. TASK_RUNNING
bir işlemin planlanabileceği anlamına gelir.
Gerçekleştirilirse, sinyal işleyicisi “yavaş” sistem çağrısı tamamlanmadan önce çalıştırılır. syscall
Varsayılan olarak tamamlanmaz.
Eğer SA_RESTART
bayrak set, syscall
sinyal işleyici bittikten sonra yeniden başlatılır.
Referanslar