当前位置:   article > 正文

Linux 操作系统:信号_man signal

man signal

1 信号

在 Linux 操作系统中,为了响应各种各样得事件,定义了非常多得信号。可以通过命令 kill -l, 查看所有得信号。


# 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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

信号的作用可以通过命令 man 7 signal 命令查看。


Signal     Value     Action   Comment
──────────────────────────────────────────────────────────────────────
SIGHUP        1       Term    Hangup detected on controlling terminal
                              or death of controlling process
SIGINT        2       Term    Interrupt from keyboard
SIGQUIT       3       Core    Quit from keyboard
SIGILL        4       Core    Illegal Instruction


SIGABRT       6       Core    Abort signal from abort(3)
SIGFPE        8       Core    Floating point exception
SIGKILL       9       Term    Kill signal
SIGSEGV      11       Core    Invalid memory reference
SIGPIPE      13       Term    Broken pipe: write to pipe with no
                              readers
SIGALRM      14       Term    Timer signal from alarm(2)
SIGTERM      15       Term    Termination signal
SIGUSR1   30,10,16    Term    User-defined signal 1
SIGUSR2   31,12,17    Term    User-defined signal 2
……
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

一旦信号产生,就需要对信号进行处理,对信号的处理有三种方式:

  1. 执行默认的操作。Linux 对每种信号都规定了默认操作

  2. 捕捉信号。可以为信号定义一个信号处理函数。当信号发生时,就执行相应的信号处理函数。

  3. 忽略信号。不希望处理某些信号的时候,就可以忽略该信号。但有两个信号是无法捕捉和忽略的,即 SIGKILL 和 SEGSTOP, 它们用于在任何时候中断和结束某一进程。

信号处理最常见的流程分为两步:第一步是注册信号处理函数;第二步时发送信号。

2 注册信号处理函数

2.1 signal 函数

如果不想某个信号执行默认操作,一种方法就是对特定的信号注册相应的信号处理函数,设置信号处理方式的是 signal 函数。


typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
  • 1
  • 2
  • 3

其实就是定义一个方法,将这个方法和某个信号关联起来。当这个进程遇到这个信号的时候,就执行这个方法。

注意,signal 不是系统调用,而是 glibc 封装的一个函数。这样就像 man signal 里面写的一样,不同的实现方式,设置的参数会不同,会导致行为的不同。

2.2 sigaction 函数

在 Linux 下面执行 man signal 的话,会发现 Linux 不建议直接使用这个方法,而是改用 sigaction。定义如下:


int sigaction(int signum, const struct sigaction *act,
                     struct sigaction *oldact);
  • 1
  • 2
  • 3

这两者的区别在哪里呢?其实它还是将信号和一个动作进行关联,只不过这个动作由一个结构 struct sigaction 表示了。

glibc 里面有个文件 syscalls.list。这里面定义了库函数调用哪些系统调用,在这里找到 sigaction。


sigaction    -       sigaction       i:ipp   __sigaction     sigaction
  • 1
  • 2

接下来,在 glibc 中,__sigaction 会调用 __libc_sigaction,并最终调用的系统调用是 rt_sigaction。

2.3 小结

在用户程序里面,有两个信号处理函数可以调用,一个是 signal, 一个是 sigaction, 推荐使用 sigaction。

用户程序调用的是 Glibc 里面的函数, signal 调用的是 __sysv_signal, 里面默认设置了一些参数,使得 signal 的功能收到了限制,sigaction 调用的是 __sigaction, 参数用户可以任意设定。

无论是 __sysv_signal 还是 __sigaction, 调用的都是统一的一个系统调用 rt_sigaction.

在内核中, rt_sigaction 调用的是 do_sigaction 设置信号处理函数。在每一个进程的 task_struct 里面,都有一个 sighand 指向 struct sighand_struct,里面是一个数组,下标是信号,里面的内容是信号处理函数。
在这里插入图片描述

3 发送信号

有时候,在终端输入某些组合的时候,会给进程发送信号,例如, CTRL+C 产生 SIGINT 信号, CTRL+Z 产生 SIGTSTP 信号。

有的时候,硬件异常也会产生信号。比如,执行了除以 0 的指令,CPU 就会产生异常,然后把 SIGFPE 信号发送给进程。再如,进程访问了非法内存,内存管理模块就会产生异常,然后把信号 SIGSEGV 发送给进程。

中断和信号都可以由硬件产生,对于中断和信号还是要加以区别。中断要注册中断处理函数,但是中断处理函数是在内核驱动里面的,信号也是注册信号处理函数,信号处理函数是在用户态进程里面的。

我们可以通过 kill 或者 sigqueue 系统调用,发送给某个进程,也可以通过 tkill 或者 tgkill 发送信号给某个进程。虽然方式多种多样,但是最终都是调用了 do_send_sig_info 函数,将信号放在相应的 task_struct 的信号数据结构中。

  • kill->kill_something_info->kill_pid_info->group_send_sig_info->do_send_sig_info

  • tkill->do_tkill->do_send_specific->do_send_sig_info

  • tgkill->do_tkill->do_send_specific->do_send_sig_info

  • rt_sigqueueinfo->do_rt_sigqueueinfo->kill_proc_info->kill_pid_info->group_send_sig_info->do_send_sig_info

do_send_sig_info 会调用 send_signal, 进而调用 __send_signal。

在这里插入图片描述

参考文章:
信号:项目组A完成了,如何及时通知项目组B?
Linux 进程学习(四)------ sigaction 函数
Linux kill命令

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/864794
推荐阅读
相关标签
  

闽ICP备14008679号