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

C 有没有办法测试我是否在信号处理器中?,c,signals,signal-handling,async-safe,C,Signals,Signal Handling,Async Safe,我必须在一个日志模块上工作,这个模块可以在一个大型项目的不同地方调用。我遇到的问题是,有时可能会从信号处理程序中执行的代码调用模块。通常,日志模块包括使用localtime和strftime的时间数据,但这些调用当然不是异步信号安全的,如果从信号处理程序中调用,则可能导致死锁。在GNU/Linux系统上,除了让每个信号处理程序在处理时设置一个标志外,还有什么方法可以判断我的代码当前是否在信号处理程序上下文中执行?我认为简化我们的信号处理程序会更好,但在这种情况下,我无法选择在何处调用日志模块。如

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

您的系统是否有SIGPUNDING?我不知道在信号处理过程中该函数的行为是什么。但是,如果它返回一个set标志,如果有任何信号挂起,您可能会感到悲观并跳过异步不安全调用。

首先,您的问题是,我是否在信号处理程序中?没有明确的答案。考虑下面的代码:

#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_掩码中,使用sigaction安装信号处理程序。然后,您可以使用sigprocmask检查当前的信号掩码,如果指定的信号在信号掩码中,这意味着信号处理程序已被调用且尚未返回,返回将恢复原始信号掩码。

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


顺便说一句:您不需要单独的进程来接收消息,您可以将消息发送到自己的进程,并将管道的读取端添加到fd_集合中,前提是您的程序位于select或poll循环中,或者定期对其进行轮询。

我认为sigpending仅在信号传递之前设置。一旦输入了信号处理程序,信号就不会被设置为挂起。此外,您试图做的也是反常的。你不能从信号手柄上跳远参见sigjump等人。另外,stdio函数不被认为是信号安全的,它们可以调用malloc,等等。哎呀,我对R的程序进行了评论。这应该是反常的。很抱歉我喜欢这个答案,因为它提供了一个很好的方法来做事情,但如果不需要的话,我真的不想添加一个单独的进程并通过管道发送所有日志消息。我仍然希望有一种简单的方法来检测我是否在信号处理器中;操作系统似乎不难知道。您可以将消息发送到自己的进程,并将管道添加到fd_集中,因为您处于选择或轮询循环中。从信号处理程序进行系统调用通常是个坏主意……您确定您在这里受到保护吗?是的,这是一个问题。如果我在信号处理程序中,我希望避免不安全的系统调用,但是如果代码在我不在信号处理程序中时被调用,则可以使用它们;我将不得不考虑这一点,以及它在信号处理器中的实际意义。我主要关心的是知道我是否可能在代码的其他部分中持有一个锁,并且由于这类东西无论如何都不会被设置为jmp/longjmp安全的,所以我不会在任何可能导致该问题的地方使用jmp函数。不过我喜欢sigaction/sau面具的建议,这听起来基本上正是我想要的。