2.2 core相关的信号处理的问题 问题一:信号处理函数是否会改变函数的执行流程?没有exit的结果是什么 注意,我们看到上文的DumpTraceBack函数中,结尾有关键的一句exit(); 如果没有这一句,crash会一直进行下去:因为原线程的执行流程并没有被打断,在信号处理函数执行完毕之后,会继续运行到产生crash信号的那一行代码。 问题二:为何存在crash堆栈没有打印完全的情况? 从问题一出发,因为某个线程调用了exit,所以所有的线程都会退出。另外,exit 会清理该进程申请的所有资源,也会刷新对应的键盘缓冲区,所以会导致某些线程的堆栈并没有被完全打印。这里需要注意一点:exit是一个c语言中的函数,不是一个c++中的函数,自然不满足cpp中的RAII原则,因此,exit不会清理对应的C++对象,包括ostream、特定对象的析构函数等等。 问题三:多线程中,如果有多个core信号同时到达,或者嵌套,该如何处理? 宏观上,一个进程内部的多线程是可以同时运行信号处理程序的。我们可以通过在中断处理加入sleep函数来验证。 void DumpTraceback(int signal)
{
std::thread::id tid = std::this_thread::get_id();
printf(">>>> dumping :%ld\n", tid);
const int len = 200;
void* buffer[len];
int nptrs = ::backtrace(buffer, len);
char** strings = ::backtrace_symbols(buffer, nptrs);
printf("id:%ld, sig:%d nptrs:%d\n", tid, signal, nptrs);
if (strings) {
for (int i = 0; i < nptrs; ++i) {
printf("line=%d||trace_back=%s||\n", i, strings[i]);
sleep(1);//这里加上sleep,观察信号处理函数
}
free(strings);
}
exit(1);
}
我们测试一下,如果在信号处理函数中进一步产生core对应的信号,行为如何? 对应信号被处理时,该信号处于被屏蔽的状态,所以如果信号处理函数本身产生了对应的信号,结果是未定义的。以目前linux 系统的实现来看,如果信号处理函数本身的代码运行时产生了SIGBUS, SIGFPE, SIGILL, or SIGSEGV等信号,那么会出发系统默认的信号处理函数进行处理,继续crash。注意,这只是系统的默认行为。实际上,我们是可以通过SA_RESETHAND这个标志位,来决定信号处理期间,对应信号的处理行为. 如果SA_RESETHAND 设置为1,表示信号处理期间,重制信号处理函数到默认行为。 #include<signal.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
volatile char *ptr;
static void DisasterSignals(int signal)
{
/* We cannot save the situation, the purpose of catching the signal is
only to do something clever to aid debugging before we go. */
write(1, "11\n", 3);
*ptr = 1;
write(1, "13\n", 3);
abort(); /* This should give us the expected core dump (if we survive to this point) */
}
struct sigaction sa = {}; /* initialised to all zero (I vote for GCC style breach of standard here) */
int main()
{
sa.sa_handler = DisasterSignals;
sa.sa_flags = /*SA_RESETHAND | */SA_NODEFER; /* To have or have not */
sigaction(SIGSEGV, &sa, NULL);
write(1, "25\n", 3);
*ptr = 1;
}
|