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 signal handling.
-
It's often a bad idea to have system calls from signal handlers...are you sure you're protected here? – JXG Sep 07 '11 at 12:27
-
Yeah, that's sort of the problem. I want to avoid unsafe system calls *if* I'm in a signal handler, but have them available if the code is called when I'm not in a signal handler. – Jay Walker Oct 11 '11 at 14:56
3 Answers
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).

- 208,859
- 35
- 376
- 711
-
That's an interesting point about the longjmp (or siglongjmp); I'll have to think about that and what it actually means to be in a signal handler. My main concern is knowing whether or not I could be in some other part of the code that could be holding a lock, and since that sort of thing wouldn't be setjmp/longjmp safe anyway I don't really use the jmp functions anywhere they could cause that problem. I like the sigaction/sa_mask suggestion though, that sounds like basically exactly what I'm looking for. – Jay Walker Oct 11 '11 at 15:09
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.

- 43,142
- 8
- 66
- 109
-
Also, what you try to do is perverse. You don't longjump from a signal handler(see sigjump et.al). Also, the stdio functions are not considerd signal-safe (they maight call malloc(), etc.) – wildplasser Sep 03 '11 at 14:38
-
Oops, I commented on the program by R. which was supposed to be perverse. Sorry! – wildplasser Sep 03 '11 at 15:06
-
I like this answer in that it gives a sound way to do things, but I don't really want to add a separate process and send all log messages through a pipe if I don't have to. I still wish there were an easy way to detect whether I was in a signal handler; it seems like it shouldn't be difficult for the OS to know. – Jay Walker Oct 11 '11 at 15:02
-
1You can send the messages to your own process and add the pipe to the fd_set (given you are in a select or poll loop) – wildplasser Oct 11 '11 at 16:37
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.

- 34,200
- 7
- 63
- 71
-
1I think that sigpending is set only before the signal is delivered. Once the signal handler is entered, the signal isn't set as "pending". – Jay Walker Mar 05 '10 at 22:53