I'm having to work on a logging module that can be called from various places in a large project. The problem I have is that sometimes the module may be called from code executed inside a signal handler. Normally, the logging module includes time data using localtime() and strftime(), but of course these calls are not async-signal safe, and can cause deadlocks if called from within a signal handler. Is there any way (on a GNU/Linux system) to tell whether or not my code is currently executing in a signal handler context, apart from e.g., having every signal handler set a flag while processing? I think it would be better to simplify our signal handlers, but in this case I don't have a choice as to where the logging module might be called. It would be nice if I could test and just omit the timestamp information if the module is called during si开发者_高级运维gnal handling.
First of all, your question ("Am I in a signal handler?") does not have a well-defined answer. Consider the following code:
#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);
}
With that said, there is a technique you could use to answer this question in a meaningful way for many programs. Choose a signal you don't intend to use, and add it to the sa_mask
for all the signals you handle, installing the signal handlers using sigaction
. Then you can use sigprocmask
to check the current signal mask, and if your designated signal is in the signal mask, that means a signal handler has been invoked and has not yet returned (returning would restore the original signal mask).
The easiest way is to log via a (named) pipe (writes upto PIPE_MAX are atomic) , or via an UDP socket (idem). The message origin can be set by the function generating the message. Of course you'll need a process that actually reads and processes the messages, but it can be kept outside the context of a signal handler.
BTW: you don't need a separate process to recieve the messages, you can send the messages to your own process and add (the reading end of) the pipe to the fd_set (given your program sits in a select or poll loop), or poll it periodically.
Does your system have sigpending
? I don't know what the behavior of that function is during a signal handler. If it returns a set flag, though, you could be pessimistic and skip async-unsafe calls if any signals are pending.
精彩评论