How can I register a signal handler for ALL signal, available on the running OS, using signal(3)?
My code looks like this:
void sig_handler(int signum)
{
printf("Received signal %d\n", signum);
}
int main()
{
signal(ALL_SIGNALS_??, sig_handler);
while (1) {
sleep(1);
};
return 0;
}
A signal handler is a function which is called by the target environment when the corresponding signal occurs. The target environment suspends execution of the program until the signal handler returns or calls longjmp() . Signal handlers can be set with signal() or sigaction() .
signal() sets the disposition of the signal signum to handler, which is either SIG_IGN, SIG_DFL, or the address of a programmer- defined function (a "signal handler"). If the signal signum is delivered to the process, then one of the following happens: * If the disposition is set to SIG_IGN, then the signal is ignored.
Signal handlers run concurrently with main program (in same process). <= 1 pending signal per type per process No Queue! Just a bit per signal type. Signals of type S discarded while process has S signal pending.
A Default signal handler is associated with every signal that the kernel runs when handling that signal. The action that a script or program performs when it receives a signal is called the default actions. A default signal handler handles these types of different default actions.
Most systems have a macro NSIG
or _NSIG
(the former would not be available in standards-conformance mode since it violates the namespace) defined in signal.h
such that a loop for (i=1; i<_NSIG; i++)
will walk all signals. Also, on POSIX systems that have signal masks, CHAR_BIT*sizeof(sigset_t)
is an upper bound on the number of signals which you could use as a fallback if neither NSIG
nor _NSIG
is defined.
Signal handlers have to deal with reentrancy concerns and other problems. In practice, it's often more convenient to mask signals and then retrieve them from time to time. You can mask all signals (except SIGSTOP
and SIGKILL
, which you can't handle anyway) with this:
sigset_t all_signals;
sigfillset(&all_signals);
sigprocmask(SIG_BLOCK, &all_signals, NULL);
The code is slightly different if you're using pthreads. Call this in every thread, or (preferably) in the main thread before you create any others:
sigset_t all_signals;
sigfillset(&all_signals);
pthread_sigmask(SIG_BLOCK, &all_signals, NULL);
Once you've done that, you should periodically call sigtimedwait(2)
like this:
struct timespec no_time = {0, 0};
siginfo_t result;
int rc = sigtimedwait(&all_signals, &result, &no_time);
If there is a signal pending, information about it will be placed in result
and rc
will be the signal number; if not, rc
will be -1 and errno
will be EAGAIN
. If you're already calling select(2)
/poll(2)
(e.g. as part of some event-driven system), you may want to create a signalfd(2)
instead and attach it to your event loop. In this case, you still need to mask the signals as shown above.
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