signal的原理这里不打算多讲,这里主要讲一下应用
man 7 signal,可以看到一些关于signal的介绍:
每个信号都对应着一个action,默认的有:Term, Ign,core,Stop,Cont, 文档上明确的写着是以进程为修改单位的,所有的线程的action都相同:
The signal disposition is a per-process attribute: in a multithreaded application, the disposition of a particular signal is the same for all threads.
信号对应的action被执行了才称之为这个signal被delivered,signal已经发出了,但是没有执行action,称之为signal被pending了,每个线程都可以单独设置mask,来block一些信号,当有对应的signal到来时,这些信号就被pending了,直到再次设置mask在unblock这些signal, pending的signal才会被执行。
signal和默认的action直接的对应关系为:
core就是产生core dump(需要kernel打开coredump选项支持,ulimit -c unlimited不限制core文件大小,core文件的路径可读写),因此可以看出并不是所有的死机都会产生core文件,测试coredump是否生效可以使用下面命令:
kill -s 11 pid
linux有时会出现应用莫名奇妙的死机,死机毫无规律可循,这时就可以考虑捕获信号,如果了解过kernel的原理就会知道死机都是由信号引起的。
捕获信号的本质就是改变action,action其实就是一个函数指针,改变这个函数指针以指向自定义的函数,sigaction(2) or signal(2)都可以进行捕获,但是signal(2)缺乏移植性。
注意这些signal_handler()是在用户空间执行的,内核采用了Trampoline机制,感兴趣的可以查阅相关资料了解一下。
下面给出一个捕获的例子:
#if DEBUG_SEGV_HANDLER
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_sigaction = handle_sigsegv;
sa.sa_flags = SA_SIGINFO;
sigaction(SIGSEGV, &sa, NULL);
sigaction(SIGILL, &sa, NULL);
sigaction(SIGFPE, &sa, NULL);
sigaction(SIGBUS, &sa, NULL);
#endif
#if DEBUG_SEGV_HANDLER
static
void handle_sigsegv(int sig, siginfo_t *info, void *ucontext)
{
long ip;
ucontext_t *uc;
uc = ucontext;
ip = uc->uc_mcontext.gregs[REG_EIP];
fdprintf(2, "signal:%d address:0x%lx ip:0x%lx\n",
sig,
/* this is void*, but using %p would print "(null)"
* even for ptrs which are not exactly 0, but, say, 0x123:
*/
(long)info->si_addr,
ip);
{
/* glibc extension */
void *array[50];
int size;
size = backtrace(array, 50);
backtrace_symbols_fd(array, size, 2);
}
for (;;) sleep(9999);
}
#endif