繁体   English   中英

Longjmp退出信号处理程序?

[英]Longjmp out of signal handler?

从问题:

在C中使用setjmp和longjmp是不错的编程习惯?

其中两条评论说:

“你不能在信号处理程序中抛出异常,但你可以安全地做一个longjmp - 只要你知道你在做什么。 - Dietrich Epp 8月31日19:57 @Dietrich:+1你的评论。这是一个鲜为人知且完全不被重视的事实。在不使用信号处理程序的longjmp的情况下,有许多问题无法解决(令人讨厌的竞争条件)。阻塞系统调用的异步中断是典型的例子。“

我的印象是内核在遇到异常情况时调用信号处理程序(例如除以0)。 此外,如果您专门注册它们,它们只会被调用。

这似乎意味着(对我来说)它们不会通过您的正常代码调用。

继续这个想法...我理解的是setjmp和longjmp用于将堆栈折叠到先前的点和状态。 我不明白在调用信号处理程序时如何折叠堆栈,因为它从内核调用作为一次性环境而不是从您自己的代码调用。 从信号处理程序到堆栈的下一个东西是什么!?

内核“调用”信号处理程序的方式是通过中断线程,将信号掩码和处理器状态ucontext_t在堆栈上的ucontext_t结构中(在下面,在增长的实现中)中断代码的堆栈指针,然后重新启动执行在信号处理程序的地址。 内核不需要跟踪任何“此进程处于信号处理程序”状态; 这完全是创建新调用框架的结果。

如果被中断的线程处于系统调用的中间,则内核将退出内核空间代码并调整返回地址以重复系统调用(如果为信号设置了SA_RESTART并且系统调用是可重新启动的)或者把EINTR放在返回码中(如果不能重启)。

应该注意的是, longjmp是异步信号不安全的。 这意味着如果从信号处理程序调用它,如果信号中断了另一个async-signal-unsafe函数,它将调用未定义的行为。 但只要中断的代码不使用库函数,或者只使用标记为异步信号安全的库函数,从信号处理程序调用longjmp是合法的。

最后,我的答案基于POSIX,因为问题是标记为unix 如果这个问题只是关于纯C的问题,我怀疑答案有些不同,但是如果没有POSIX,信号就毫无用处......

longjmp 不执行正常的堆栈展开 相反,堆栈指针只是从setjmp保存的上下文中恢复。

下面是一个说明如何在代码中使用非异步安全的关键部分。 建议例如在关键代码期间屏蔽有问题的信号。

在大多数系统中,信号处理程序具有自己的堆栈,与主堆栈分开。 这就是为什么你可以从一个处理程序中解脱出来的原因。 我认为这不是一件明智的事。

值得一读: http : //man7.org/linux/man-pages/man2/sigreturn.2.html关于Linux如何处理信号处理程序调用,在这种情况下它如何管理信号处理程序退出,我读这个建议从信号处理程序执行longjmp()(导致不调用sigreturn())可能充其量只是“未定义”...也必须考虑setjmp()的哪个线程(以及用户堆栈)被调用,并且随后调用了哪个线程(以及用户堆栈)longjmp()!

你不能使用longjmp来摆脱信号处理程序。

这样做的原因是setjmp只保存了调用约定指定应该通过普通函数调用保存的资源(进程寄存器)等。

当发生中断时,被中断的函数可能具有更大的状态,并且longjmp将无法正确恢复它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM