I have a C application running on Linux where I need to add some code to the standard signal handler. The idea was to setup my handler saving the pointer to the standard one and call the saved handler from my code. Unfortunately, neither signal() nor sigaction() return pointer to the standard handler. Both of them return NULL instead. Is there any way of doing custom handling and continuing with the standard handling without removal of the custom handler and sending the same signal again?
2 Answers
There is no "standard signal handler"; instead, there's a default action performed by the kernel when a signal is unhandled. If you want to do something when the signal is received, then defer to the default action, you can do the following at the end of your signal handler:
sigset_t set;
signal(sig, SIG_DFL);
raise(sig);
sigemptyset(&set);
sigaddset(&set, sig);
sigprocmask(SIG_UNBLOCK, &set, 0);
This is assuming you used sigaction to install your signal handler, and did not specify the SA_NODEFER or SA_RESETHAND flags. It's also possible to achieve what you want using those flags and simply calling raise, but this has ugly race conditions if the signal is delivered twice in rapid succession, so you should not do it; instead use the method I suggested.
Edit: Actually you don't have to do any of the signal mask stuff, since returning from the signal handler will restore the old signal mask. Just this should work:
signal(sig, SIG_DFL);
raise(sig);
return;
- 208,859
- 35
- 376
- 711
-
Why do you want to avoid `raise`? And yes, it is impossible without calling `raise`, unless the signal is something like `SIGSEGV` or `SIGFPE` that you could generate again just by performing another null pointer dereference or division-by-zero... – R.. GitHub STOP HELPING ICE Sep 12 '11 at 14:13
-
This is a better answer than mine – Anya Shenanigans Sep 12 '11 at 14:25
-
1The disadvantage of this solution is that you change the handler to `SIG_DFL` for good. It doesn't work if you only want to invoke default handler but keep your own as the signal handler. – Adam Badura Nov 10 '14 at 11:29
-
@AdamBadura: For the most part the only interesting default handler is abnormal process termination, which can only happen once anyway... – R.. GitHub STOP HELPING ICE Nov 11 '14 at 03:23
-
@R.. Likely yes. But still I think it is reasonable to ask for general solution. – Adam Badura Nov 11 '14 at 08:27
When the call to signal() or sigaction() returns NULL, it implies SIG_DFL (i.e. default signal handler)
If you're using signal(), the handler is supposed to be reset when the handler is called, you can issue raise(SIGNAL) as the last line in the signal handler and it should invoke the default handler.
If you're using sigaction() then you should pass in SA_RESETHAND as one of the flags, which will allow you to use the raise(SIGNAL) call in that handler.
The vast majority of default signal handlers will terminate the application, so this 'one shot' replacement will work. You can add a sigaction() call after the raise call to store the new handler again e.g.
void sighandler(int signum)
{
// Do my stuff
raise(signup);
signal(signum, sighandler);
}
- 91,618
- 3
- 107
- 122
-
-
1If the signal in question is `SIGSEGV`, `SIG_DFL();` should work. ;-) – R.. GitHub STOP HELPING ICE Sep 12 '11 at 14:15
-
If your signal handler was installed with `SA_SIGINFO`, you can look at `si->si_addr` to find the faulting address and attempt to access this address again. That may give you the `SIGBUS` you want without a call to `raise`, but I'm not sure why you're so adverse to calling `raise`. – R.. GitHub STOP HELPING ICE Sep 12 '11 at 16:43