在linux中处理SIGBUS

时间:2013-10-17 00:07:12

标签: c linux signals

在我的一个程序中,当尝试访问无法获取内存页面的mmap内存位置(因为底层物理内存耗尽)并且程序因SIGBUS而崩溃时,我会点击“SIGBUS”。 / p>

我计划注册一个SIGBUG信号处理程序以避免崩溃。但是,我不想从SIGBUS处理程序退出()程序。我试图看看是否有任何方式优雅地报告ENOMEM并继续该程序与其他工作。

我可以执行以下操作吗?代码如下所示:

mem_p->head = MY_HEAD_MAGIC;   /* this line could trigger SIGBUS */
if (sigbus_happened) {
    sigbus_happened = FALSE;
    do_something_else();   
    return ENOMEM;
}

和信号处理程序:

void signal_handler (int sig)
{
   if (sig == SIGBUS)
      sigbus_happened = TRUE;
}   

上述工作会不会崩溃?

感谢。

1 个答案:

答案 0 :(得分:3)

您展示的代码可能会违背您的预期。这是因为编译器可以自由安排代码,以便在分配sigbus_happened之前“记住”mem_p->head的值。因此,即使信号处理程序执行,您的代码也可能无法检测到该标志已被设置。至少,您需要创建变量volatile

最好只检查mmap()调用是否失败。您可以通过检查调用是否返回值MAP_FAILED来执行此操作。如果调用失败,请不要尝试访问指针值。

您尝试捕获SIGBUS会提醒异常处理。 C没有C ++样式的异常处理(尽管存在模仿它们的宏包,例如cexcept)。但是,使用setjmp()longjmp()更像是例外工作方式的方式来跟踪您的模型。 setjmp()保存现有的堆栈上下文并返回0longjmp()会将代码返回到已保存的上下文,并导致setjmp()返回非0值。

从信号处理程序中,最好使用POSIX sigsetjmp()siglongjmp(),以便在调用信号处理程序之前被C运行时或操作系统阻止的任何信号都会重置为他们在返回保存的背景时所具有的价值。

jmp_buf *sigbus_jmp; // global

void signal_handler (int sig)
{
   if (sig == SIGBUS) {
      if (sigbus_jmp) siglongjmp(*sigbus_jmp, 1);
      // no one to catch the error, so abort
      abort();
    }
}

    //...
    jmp_buf sigbus_jmpbuf;
    sigbus_jmp = &sigbus_jmpbuf;
    if (sigsetjmp(sigbus_jmpbuf, 1) == 0) {
        // try
        mem_p->head = MY_HEAD_MAGIC;   /* this line could trigger SIGBUS */
    } else {
        // catch
        do_something_else();   
        return ENOMEM;
    }
    sigbus_jmp = 0;