Linux信号和常见几种信号捕捉举例

本文阅读量 Posted by Kird on 2020-02-06
信号是Linux系统进程间通信的一种方式,本文总结运维过程常见的几种信号。

软中断信号(signal,又简称为信号)用来通知进程发生了异步事件。进程之间可以互相通过系统调用kill发送软中断信号。内核也可以因为内部事件而给进程发送信号,通知进程发生了某个事件。注意,信号只是用来通知某进程发生了什么事件,并不给该进程传递任何数据。
收到信号的进程对各种信号有不同的处理方法:

  • 第一种是捕获。类似中断的处理程序,对于需要处理的信号,进程可以指定处理函数,由该函数来处理。
  • 第二种方法是忽略。忽略某个信号,对该信号不做任何处理
  • 第三种方法是默认,对该信号的处理保留系统的默认值,这种缺省操作,对大部分的信号的缺省操作是使得进程终止。进程通过系统调用signal来指定进程对某个信号的处理行为。

常见几种信号

我们使用 kill -l 命令可以查看系统定义的信号列表,每个编号都有一个宏与之对应,可以在 /usr/include/asm/signal.h 中查看,下图中 1-31号为普通信号,34-36号信号为实时信号。

以下列出在运维过程中常见的几种信号,做一个总结。

信号名 信号值 触发 系统默认处理方式
SIGINT 2 CTRL+C硬件驱动发出 终止运行
SIGQUIT 3
SIGKILL 9 kill命令发出 终止运行
SIGUSR1 10 kill命令发出 忽略
SIGSEGV 11 段错误时候触发 终止运行
SIGUSR2 12 kill命令发出 忽略
SIGTERM 15 kill命令发出
SIGCHLD 17 子进程退出时发出给父进程
SIGCONT 18 kill命令发出,程序收到SIGSTOP或SIGSTOP停止后,收到SIGCONT会继续运行 使进程继续运行
SIGSTOP 19 kill命令发出,和SIGTSTP作用类似 使进程暂停运行
SIGTSTP 20 CTRL+Z硬件驱动发出 使进程暂停运行

其中,SIGKILL 和 SIGSTOP 不能被忽略和捕捉,其他信号均可以捕捉处理。

信号捕捉举例

以下通过简单的程序对常见的几个信号进行捕捉处理。

捕捉SIGINT和SIGTSTP

src/signal_catch.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>

//定义信号处理函数和信号值
void sig_hand(int signo)
{
printf("%d,%d occured\n",getpid(),signo);
}
int main(void)
{
//向内核登记信号处理函数及信号值
if(signal(SIGTSTP,sig_hand) == SIG_ERR){ //ctrl+c
perror("error");
}
if(signal(SIGINT,sig_hand) == SIG_ERR){ //ctrl+z 捕获操作
//if(signal(SIGINT,SIG_IGN) == SIG_ERR){ //ctrl+z 忽略信号
//if(signal(SIGINT,SIG_DFL) == SIG_ERR){ //ctrl+z 默认信号
perror("error");
}
int i;
for(i=0; i<10;i++){
//printf("%d",i);
printf("%d running %d \n",getpid(),i);
sleep(1);
}
return 0;
}

编译运行后,通过CTRL+CCTRL+Z向程序发送信号SIGINT和SIGTSTP,程序收到SIGINT本应该终止运行,收到SIGTSTP本应该暂停运行,通过13行和16行代码中,将信号进行捕捉处理,到自定义的sig_hand 函数中,自定义处理。程序运行结果为:

模拟段错误,忽略SIGSEGV信号

正常程序运行时,收到SIGSEGV信号信号时,默认终止程序并报错Segmentation fault.
下面这个程序,模拟空指针导致内存访问错误,程序通过处理SIGSEGV信号,可以继续运行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <setjmp.h>
static jmp_buf env;
//定义信号处理函数和信号值
void sig_hand_coredump(int signo)
{
printf("%d,%d Segmentation fault\n",getpid(),signo);
longjmp(env,1);
}

int main(int argc,char **argv)
{
int r;
r = setjmp(env);
if (r==0){
signal(SIGSEGV,sig_hand_coredump);
printf("making coredump...");
int *p=NULL;
(*p)=0;
}
else
{
printf("making coredump done!!! running after coredump!!!\n");
}
return 0;
}

运行结果如下:



支付宝打赏 微信打赏

赞赏支持一下