linux信号量对mysql_Linux使用信号量监控程序异常退出

本文介绍了如何使用Linux信号量作为黑匣子程序,监控程序异常退出,以定位崩溃原因。通过定义信号处理函数保存崩溃前的堆栈信息,避免依赖大型core文件。示例程序展示了如何捕获并处理SIGHUP、SIGINT、SIGQUIT等异常信号,并使用backtrace和backtrace_symbols获取调用栈信息。在栈溢出的极端情况下,通过可替换信号栈优化确保信号处理函数能够正常工作。
摘要由CSDN通过智能技术生成

1.何为黑匣子程序及其必要性

飞机上面的黑匣子用于飞机失事后对事故的时候调查,同理,程序的黑匣子用于程序崩溃后对崩溃原因进程定位。其实Linux提供的core dump机制就是一种黑匣子(core文件就是黑匣子文件)。但是core文件并非在所有场景都适用,因为core文件是程序崩溃时的内存映像,如果程序使用的内存空间比较大,那产生的core文件也将会非常大,在64bit的操作系统中,该现象更为显著。但是,其实我们定位程序崩溃的原因一般只需要程序挂掉之前的堆栈信息、内存信息等就足够了。所以有的时候没有必要使用系统自带的core文件机制。

阅读本文前,推荐先看一下我的另外一篇博客《Linux 的 core 文件》,里面讲解了core文件,并介绍了一些Linux信号的基本知识。

2. 黑匣子程序设计

程序异常时,往往会产生某种信号,内核会对该信号进行处理。所以设计黑匣子程序的实质就是我们定义自己的信号处理函数,来代替内核的默认处理。在我们的信号处理函数中,我们可以将我们想要的信息保存下来(比如程序崩溃时的堆栈信息),以方便后面问题的定位。

下面我们先给出一个我写的程序,然后边分析程序边讲具体如何设计一个黑匣子程序:

#include

#include

#include

#include

#include

#include

#include

#include

/* 定义一个数据结构用来保存信号 */

typedef struct sigInfo

{

int     signum;

char    signame[20];

} sigInfo;

/* 增加我们想要捕捉的异常信号,这里列举了6个 */

sigInfo sigCatch[] = {

{1, "SIGHUP"}, {2, "SIGINT"}, {3, "SIGQUIT"},

{6, "SIGABRT"}, {8, "SIGFPE"}, {11, "SIGSEGV"}

};

/* 我们自定义的信号处理函数 */

void blackbox_handler(int sig)

{

printf("Enter blackbox_handler: ");

printf("SIG name is %s, SIG num is %d\n", strsignal(sig), sig);

// 打印堆栈信息

printf("Stack information:\n");

int j, nptrs;

#define SIZE 100

void *buffer[100];

char **strings;

nptrs = backtrace(buffer, SIZE);

printf("backtrace() returned %d addresses\n", nptrs);

strings = backtrace_symbols(buffer, nptrs);

if (strings == NULL)

{

perror("backtrace_symbol");

exit(EXIT_FAILURE);

}

for(j = 0; j < nptrs; j++)

printf("%s\n", strings[j]);

free(strings);

_exit(EXIT_SUCCESS);

}

/* 有bug的程序,调用该程序,将随机产生一些异常信号 */

void bug_func()

{

int rand;

struct timeval tpstart;

pid_t  my_pid = getpid();

// 产生随机数

gettimeofday(&tpstart, NULL);

srand(tpstart.tv_usec);

while ((rand = random()) > (sizeof(sigCatch)/sizeof(sigInfo)));

printf("rand=%d\n", rand);

//随机产生异常信号

switch(rand % (sizeof(sigCatch)/sizeof(sigInfo)))

{

case 0:

{

// SIGHUP

kill(my_pid, SIGHUP);

break;

}

case 1:

{

// SIGINT

kill(my_pid, SIGINT);

break;

}

case 2:

{

// SIGQUIT

kill(my_pid, SIGQUIT);

break;

}

case 3:

{

// SIGABRT

abort();

break;

}

case 4:

{

// SIGFPE

int a = 6 / 0;

break;

}

case 5:

{

// SIGSEGV

kill(my_pid, SIGSEGV);

break;

}

default:

return;

}

}

int main()

{

int i, j;

struct  sigaction   sa;

// 初始化信号处理函数数据结构

memset(&sa, 0, sizeof(sa));

sa.sa_handler = blackbox_handler;

sigemptyset(&sa.sa_mask);

sa.sa_flags = 0;

for (i = 0; i < sizeof(sigCatch)/sizeof(sigInfo); i++)

{

// 注册信号处理函数

if(sigaction(sigCatch[i].signum, &sa, NULL) < 0)

{

return EXIT_FAILURE;

}

}

bug_func();

while(1);

return EXIT_SUCCESS;

}

2.1 定义一些数据结构

这里我们定义了一个sigInfo的数据结构,用来保存信号。利用这个数据结构我们可以将信号值与信号名映射起来。你可以在你的系统中使用 kill –l 命令去查看他们的对应关系。当然,在程序中,如果得到了信号值,也可以使

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值