在多线程程序中捕获SIGSEGV和SIGFPE等信号 [英] Catching signals such as SIGSEGV and SIGFPE in multithreaded program

查看:1550
本文介绍了在多线程程序中捕获SIGSEGV和SIGFPE等信号的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



在主程序中调用日志系统线程推送一个数据结构,该结构包含数据记录到FIFO队列中。



如果主程序导致SIGSEGV或其他信号被执行,则程序主线程继续执行其任务。我需要确保队列在终止之前是空的。



我的计划是使用pthread_sigmask阻止信号http://man7.org/linux/man-pages/man3/pthread_sigmask.3.html ,但只有一个线程,但阅读 http://man7.org/linux/man-pages/man7/signal上的信号列表。 7.html 我注意到:


*一个进程可能会产生一个信号(例如,当使用kill(2)发送时)或针对特定线程(例如,作为执行特定机器语言指令的结果而产生的某些信号,例如SIGSEGV和SIGFPE,是使用pthread_kill(3)针对特定线程的信号)。*


如果我在所有线程上阻塞SIGSEGV,捕获信号,那么它会捕获由不同线程引发的SIGSEGV吗?



我发现了问题在Linux中使用多线程的信号处理,但是我对于哪些信号是线程特定的以及如何捕获它们是无能为力的。

解决方案

我同意评论:在实践中捕获和处理 SIGSEGV



并且 SIGSEGV 会传送到特定的线程(请参阅这是),一个正在运行访问一些非法地址的机器指令。



所以你不能运行一个线程专门捕获 SIGSEGV 在其他线程。您可能无法轻松地对使用 signalfd(2), SIGSEGV ...



捕获(通常从其信号处理程序返回) SIGSEGV 是一种复杂的处理器专用(它不能是可移植的C代码)。您需要检查和更改处理程序中的机器状态,即修改地址空间(通过调用 mmap(2) etc ...)或修改当前线程的寄存器状态。因此,请使用 sigaction(2) SA_SIGINFO 并更改信号处理程序的第三个参数(类型 ucontext_t * )指向的机器特定状态。然后深入其中的处理器专用 uc_mcontext 字段。有乐趣更改单个寄存器等等。如果你不改变有故障线程的机器状态,执行将恢复(从 SIGSEGV 处理程序返回后)与之前相同的情况,并且立即发送另一个 SIGSEGV 信号....或者简单地,不从 SIGSEGV 处理程序(例如,使用 siglongjmp(3) abort(3) _ exit(2) ...)。



即使你碰巧做了这一切, Linux内核对这样的执行不是非常有效。所以传言,试图模仿Hurd / Mach外部寻呼机这种方式在Linux上是不是很有效率。请参见此答案 ...



当然,信号处理程序应该(参见信号(7)了解更多)异步信号安全功能。特别是,你不能原则上从它们调用 fprintf (并且你可能不能够使用可靠你的日志系统,但它可以工作在



我在 SIGSEGV 上说的内容也适用于 SIGBUS SIGFPE (以及其他线程特定的异步信号,如果存在)。


I am trying to write a multithreaded logging system for a program running on linux.

Calls to the logging system in the main program threads pushes a data structure containing the data to be logged into a FIFO queue. A dedicated thread picks the data of the queue and outputs the data, while the programs main thread continues with its task.

If the main program causes SIGSEGV or other signals to be raised I need to make sure that the queue is empty before terminating.

My plan is to block the signals using pthread_sigmask http://man7.org/linux/man-pages/man3/pthread_sigmask.3.html for all but one thread, but reading the list of signals on http://man7.org/linux/man-pages/man7/signal.7.html i noticed:

*A signal may be generated (and thus pending) for a process as a whole (e.g., when sent >using kill(2)) or for a specific thread (e.g., certain signals, such as SIGSEGV and SIGFPE, >generated as a consequence of executing a specific machine-language instruction are thread directed, as are signals targeted at a specific thread using pthread_kill(3)).*

If I block SIGSEGV on all threads but a thread dedicated to catching signals, will it then catch a SIGSEGV raised by a different thread?

I found the question Signal handling with multiple threads in Linux, but I am clueless as to which signals are thread specific and how to catch them.

解决方案

I agree with the comments: in practice catching and handling SIGSEGV is often a bad thing.

And SIGSEGV is delivered to a specific thread (see this), the one running the machine instruction which accessed to some illegal address.

So you cannot run a thread dedicated to catching SIGSEGV in other threads. And you probably could not easily use signalfd(2) for SIGSEGV...

Catching (and returning normally from its signal handler) SIGSEGV is a complex and processor specific thing (it cannot be "portable C code"). You need to inspect and alter the machine state in the handler, that is either modify the address space (by calling mmap(2) etc...) or modify the register state of the current thread. So use sigaction(2) with SA_SIGINFO and change the machine specific state pointed by the third argument (of type ucontext_t*) of the signal handler. Then dive into the processor specific uc_mcontext field of it. Have fun changing individual registers, etc... If you don't alter the machine state of the faulty thread, execution is resumed (after returning from your SIGSEGV handler) in the same situation as before, and another SIGSEGV signal is immediately sent.... Or simply, don't return normally from a SIGSEGV handler (e.g. use siglongjmp(3) or abort(3) or _exit(2) ...).

Even if you happen to do all this, it is rumored that Linux kernels are not extremely efficient on such executions. So it is rumored that trying to mimic Hurd/Mach external pagers this way on Linux is not very efficient. See this answer...

Of course signal handlers should call only (see signal(7) for more) async-signal-safe functions. In particular, you cannot in principle call fprintf from them (and you might not be able to use reliably your logging system, but it could work in most but not all cases).

What I said on SIGSEGV also holds for SIGBUS and SIGFPE (and other thread-specific asynchronous signals, if they exist).

这篇关于在多线程程序中捕获SIGSEGV和SIGFPE等信号的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆