问题:
- 当std::thread调用析构时,若thread没有正确退出(没有return),则会产生coredump,为什么?
- 若在user space捕捉SIGABRT信号,thread异常退出为何还会产生coredump?
先来看看coredump的产生
kernel space
内核在处理进程信号时,调用do_signal(arch/arm/kernel/signal.c)
1 | static int do_signal(struct pt_regs *regs, int syscall) |
接着调用get_signal处理信号,
1 | if (get_signal(&ksig)) { |
取出信号,若用户有绑定signal handler,则返回non-zero值,调用用户handler,不进行内核默认处理
1 | bool get_signal(struct ksignal *ksig) |
若用户没有绑定signal handler,则使用内核默认处理方式
若signal在coredump信号列表定义内,则会产生coredump
1 | if (sig_kernel_coredump(signr)) { |
注意SIGABRT在coredump信号定义内
1 |
显然,线程退出时,进程收到了满足coredump的信号,才会产生coredump
接着看user space的实现,线程析构时,发出了什么信号
user space
局部对象实例在离开作用域时会被调用析构函数,std线程的析构函数如下:
若线程因一些原因如busy waiting而没有退出,其joinable会为true,则析构会调用terminate
terminate默认会调用abort
看下glibc中abort的实现:
https://code.woboq.org/userspace/glibc/stdlib/abort.c.html
1 | /* Send signal which possibly calls a user handler. */ |
可以看到,abort会先发送一次SIGABRT
然后清掉用户捕捉信号的handler
再发送一次SIGABRT
conclusion
线程析构发生terminate时,会调用abort先产生一次SIGABRT
内核发现用户若有注册handler,则调用用户handler,此时不产生coredump
之后,abort函数清除掉用户的handler,再发一次ABRT信号
此时内核发现没有用户handler,走默认处理函数,ARBT信号产生coredump
所以线程异常退出产生coredump的原因是发出了SIGABRT信号
而即使在user space设置了SIGABRT的捕捉信号,由于abort函数的机制,仍然会产生coredump