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.
Signal handlers can be specified for all but two signals (SIGKILL and SIGSTOP cannot be caught, blocked or ignored). If the signal reports an error within the program (and the signal is not asynchronous), the signal handler can terminate by calling abort() , exit() , or longjmp() .
Signal handlers can be interrupted by signals, including their own. If a signal is not reset before its handler is called, the handler can interrupt its own execution. A handler that always successfully executes its code despite interrupting itself or being interrupted is async-signal-safe.
a child process inherits signal settings from its parent during fork (). When process performs exec (), previously ignored signals remain ignored but installed handlers are set back to the default handler.
It is not safe to call all functions, such as printf , from within a signal handler. A useful technique is to use a signal handler to set a flag and then check that flag from the main program and print a message if required.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With