有没有办法测试我是否在信号处理程序中?

时间:2010-03-05 21:06:19

标签: c signals signal-handling async-safe

我不得不处理一个可以从大型项目中的不同位置调用的日志记录模块。我遇到的问题是,有时可以从信号处理程序内执行的代码调用模块。通常,日志记录模块包含使用localtime()和strftime()的时间数据,但当然这些调用不是异步信号安全的,并且如果从信号处理程序中调用,则可能导致死锁。是否有任何方法(在GNU / Linux系统上)判断我的代码当前是否在信号处理程序上下文中执行,除了例如让每个信号处理程序在处理时设置标志?我认为简化我们的信号处理程序会更好,但在这种情况下,我无法选择可以调用日志记录模块的位置。如果我可以测试并且只是在信号处理期间调用模块时省略时间戳信息,那将是很好的。

3 个答案:

答案 0 :(得分:3)

首先,你的问题(“我在信号处理程序中吗?”)没有明确定义的答案。请考虑以下代码:

#include <setjmp.h>
#include <signal.h>

jmp_buf jb;
int foo(int s)
{
    longjmp(jb,1);
}

int main()
{
    if (setjmp(jb)) {
        puts("Am I in a signal handler now, or not?");
        return 0;
    }
    signal(SIGINT, foo);
    raise(SIGINT);
}

有了这个说法,你可以使用一种技术以一种有意义的方式回答这个问题。选择一个您不打算使用的信号,并将其添加到sa_mask以获取您处理的所有信号,并使用sigaction安装信号处理程序。然后你可以用sigprocmask来检查当前的信号掩码,如果指定的信号在信号掩码中,那就意味着信号处理程序已被调用但尚未返回(返回将恢复原始信号掩码)。

答案 1 :(得分:3)

最简单的方法是通过(命名)管道(写入PIPE_MAX是原子的)或通过UDP套接字(idem)进行日志记录。消息来源可以由生成消息的函数设置。当然,您需要一个实际读取和处理消息的进程,但它可以保留在信号处理程序的上下文之外。


BTW:您不需要单独的流程来接收消息,您可以将消息发送到您自己的流程并将管道添加(读取结束)到fd_set(假设您的程序位于select或poll中)循环),或定期轮询。

答案 2 :(得分:0)

您的系统是否有sigpending?我不知道在信号处理程序中该函数的行为是什么。但是,如果它返回一个设置标志,那么如果有任何信号未决,你可能会悲观并跳过异步不安全的呼叫。