If we use sigaction to define a signal handler, then why don't we need to reset the handler? If we do the use signal(sig_no,handler_func) then we must reset it. Why is this?
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
void func(int sig)
{
printf("caught signal:%d\n",sig);
// Not needed to reset handler. Why?
}
int main()
{
struct sigaction sa;
sa.sa_handler=(void*)func;
sigaction(SIGRTMIN,&sa,NULL);
kill(0,SIGRTMIN);
kill(0,SIGRTMIN);
kill(0,SIGRTMIN);
}
Output:
[root#dhcppc0 signals]# ./a.out
caught signal:34
caught signal:34
caught signal:34 (3 times signal caught by same handler without resetting handler)
The real reason goes back to some decades ago. The original signal() didn't rearm the handler. It also didn't restart interrupted system calls. The BSD guys decided to have a more "reliable" signal(), so they changed that semantics.
Since System V and BSD behaviour was so different, the POSIX commitee decided to introduce a new system call, sigaction(), with parameters to modify its behaviour. So the whole reason sigaction() exists is to have signal using code that behaves the same across Unix variants.
(Note that the bahaviour of signal() can change even when using the same libc, for instance, glibc uses BSD behaviour by default, and SYSV behaviour when _XOPEN_SOURCE is defined).
Unless you specify SA_RESETHAND in the flags, the disposition isn't changed (and therefore doesn't need to be reset)
If you were to set sa.sa_flags = SA_RESETHAND You'd need to reset it because the disposition would be reset to SIG_DFL (which is what happens with signal())
Basically, the answer to your question is "Because that's how sigaction works. Its behavior is different than signal".
Related
I was about to add an extra signal handler to an app we have here and I noticed that the author had used sigaction() to set up the other signal handlers. I was going to use signal(). To follow convention I should use sigaction() but if I was writing from scratch, which should I choose?
Use sigaction() unless you've got very compelling reasons not to do so.
The signal() interface has antiquity (and hence availability) in its favour, and it is defined in the C standard. Nevertheless, it has a number of undesirable characteristics that sigaction() avoids - unless you use the flags explicitly added to sigaction() to allow it to faithfully simulate the old signal() behaviour.
The signal() function does not (necessarily) block other signals from arriving while the current handler is executing; sigaction() can block other signals until the current handler returns.
The signal() function (usually) resets the signal action back to SIG_DFL (default) for almost all signals. This means that the signal() handler must reinstall itself as its first action. It also opens up a window of vulnerability between the time when the signal is detected and the handler is reinstalled during which if a second instance of the signal arrives, the default behaviour (usually terminate, sometimes with prejudice - aka core dump) occurs.
The exact behaviour of signal() varies between systems — and the standards permit those variations.
These are generally good reasons for using sigaction() instead of signal(). However, the interface of sigaction() is undeniably more fiddly.
Whichever of the two you use, do not be tempted by the alternative signal interfaces such as
sighold(),
sigignore(),
sigpause() and
sigrelse().
They are nominally alternatives to sigaction(), but they are only barely standardized and are present in POSIX for backwards compatibility rather than for serious use. Note that the POSIX standard says their behaviour in multi-threaded programs is undefined.
Multi-threaded programs and signals is a whole other complicated story. AFAIK, both signal() and sigaction() are OK in multi-threaded applications.
Cornstalks observes:
The Linux man page for signal() says:
The effects of signal() in a multi-threaded process are unspecified.
Thus, I think sigaction() is the only that can be used safely in a multi-threaded process.
That's interesting. The Linux manual page is more restrictive than POSIX in this case. POSIX specifies for signal():
If the process is multi-threaded, or if the process is single-threaded and a signal handler is executed other than as the result of:
The process calling abort(), raise(), kill(), pthread_kill(), or sigqueue() to generate a signal that is not blocked
A pending signal being unblocked and being delivered before the call that unblocked it returns
the behavior is undefined if the signal handler refers to any object other than errno with static storage duration other than by assigning a value to an object declared as volatile sig_atomic_t, or if the signal handler calls any function defined in this standard other than one of the functions listed in Signal Concepts.
So POSIX clearly specifies the behaviour of signal() in a multi-threaded application.
Nevertheless, sigaction() is to be preferred in essentially all circumstances — and portable multi-threaded code should use sigaction() unless there's an overwhelming reason why it can't (such as "only use functions defined by Standard C" — and yes, C11 code can be multi-threaded). Which is basically what the opening paragraph of this answer also says.
In short:
sigaction() (see here and here) is good and well-defined, but is a POSIX function and so it works only on Linux or POSIX systems. signal() (see here and here) is bad and poorly-defined, but is a C standard function and so it works on anything.
What do the Linux man pages have to say about it?
man 2 signal (see it online here) states:
The behavior of signal() varies across UNIX versions, and has also varied historically across different versions of Linux. Avoid its use: use sigaction(2) instead. See Portability below.
Portability
The only portable use of signal() is to set a signal's disposition to
SIG_DFL or SIG_IGN. The semantics when using signal() to establish a
signal handler vary across systems (and POSIX.1 explicitly permits
this variation); do not use it for this purpose.
In other words: do not use signal(). Use sigaction() instead!
This position is reiterated in the next line which states (emphasis added):
POSIX.1 solved the portability mess by specifying sigaction(2), which provides explicit control of the semantics when a signal handler is invoked; use that interface instead of signal().
What does GCC think?
From https://www.gnu.org/software/libc/manual/html_node/Basic-Signal-Handling.html#Basic-Signal-Handling (emphasis added):
Compatibility Note: As said above for signal, this function should be avoided when possible. sigaction is the preferred method.
So, if both Linux and GCC say not to use signal(), but to use sigaction() instead, that begs the question: how the heck do we use this confusing sigaction() thing!?
Usage Examples:
Read GCC's EXCELLENT signal() example here: https://www.gnu.org/software/libc/manual/html_node/Basic-Signal-Handling.html#Basic-Signal-Handling
And their EXCELLENT sigaction() example here: https://www.gnu.org/software/libc/manual/html_node/Sigaction-Function-Example.html
After reading those pages, I came up with the following technique for sigaction():
1. sigaction(), since it's the right way to attach a signal handler, as described above:
#include <errno.h> // errno
#include <signal.h> // sigaction()
#include <stdio.h> // printf()
#include <string.h> // strerror()
// Format: const char *, unsigned int, const char *
#define LOG_LOCATION __FILE__, __LINE__, __func__
#define LOG_FORMAT_STR "file: %s, line: %u, func: %s: "
/// #brief Callback function to handle termination signals, such as
/// Ctrl + C
/// #param[in] signal Signal number of the signal being handled by this
/// callback function
/// #return None
static void termination_handler(const int signal)
{
switch (signal)
{
case SIGINT:
printf("\nSIGINT (%i) (Ctrl + C) signal caught.\n", signal);
break;
case SIGTERM:
printf("\nSIGTERM (%i) (default `kill` or `killall`) signal caught.\n",
signal);
break;
case SIGHUP:
printf("\nSIGHUP (%i) (\"hang-up\") signal caught.\n", signal);
break;
default:
printf("\nUnk signal (%i) caught.\n", signal);
break;
}
// DO PROGRAM CLEANUP HERE, such as freeing memory, closing files, etc.
exit(signal);
}
/// #brief Set a new signal handler action for a given signal
/// #details Only update the signals with our custom handler if they are NOT
/// set to "signal ignore" (`SIG_IGN`), which means they are currently
/// intentionally ignored. GCC recommends this "because non-job-control
/// shells often ignore certain signals when starting children, and it is
/// important for children to respect this." See
/// https://www.gnu.org/software/libc/manual/html_node/Basic-Signal-Handling.html#Basic-Signal-Handling
/// and
/// https://www.gnu.org/software/libc/manual/html_node/Sigaction-Function-Example.html.
/// Note that termination signals can be found here:
/// https://www.gnu.org/software/libc/manual/html_node/Termination-Signals.html#Termination-Signals
/// #param[in] signal Signal to set to this action
/// #param[in] action Pointer to sigaction struct, including the callback
/// function inside it, to attach to this signal
/// #return None
static inline void set_sigaction(int signal, const struct sigaction *action)
{
struct sigaction old_action;
// check current signal handler action to see if it's set to SIGNAL IGNORE
sigaction(signal, NULL, &old_action);
if (old_action.sa_handler != SIG_IGN)
{
// set new signal handler action to what we want
int ret_code = sigaction(signal, action, NULL);
if (ret_code == -1)
{
printf(LOG_FORMAT_STR "sigaction failed when setting signal to "
"%i; errno = %i: %s\n",
LOG_LOCATION, signal, errno, strerror(errno));
}
}
}
int main(int argc, char *argv[])
{
//...
// Register callbacks to handle kill signals; prefer the Linux function
// `sigaction()` over the C function `signal()`: "It is better to use
// sigaction if it is available since the results are much more reliable."
// Source:
// https://www.gnu.org/software/libc/manual/html_node/Basic-Signal-Handling.html#Basic-Signal-Handling
// and
// https://stackoverflow.com/questions/231912/what-is-the-difference-between-sigaction-and-signal/232711#232711.
// See here for official gcc `sigaction()` demo, which this code is modeled
// after:
// https://www.gnu.org/software/libc/manual/html_node/Sigaction-Function-Example.html
// Set up the structure to specify the new action, per GCC's demo.
struct sigaction new_action;
new_action.sa_handler = termination_handler; // set callback function
sigemptyset(&new_action.sa_mask);
new_action.sa_flags = 0;
// SIGINT: ie: Ctrl + C kill signal
set_sigaction(SIGINT, &new_action);
// SIGTERM: termination signal--the default generated by `kill` and
// `killall`
set_sigaction(SIGTERM, &new_action);
// SIGHUP: "hang-up" signal due to lost connection
set_sigaction(SIGHUP, &new_action);
//...
}
2. And for signal(), even though its not a good way to attach a signal handler, as described above, it's still good to know how to use it.
Here's the GCC demonstration code copy-pasted, as it's about as good as it's going to get:
#include <signal.h>
void
termination_handler (int signum)
{
struct temp_file *p;
for (p = temp_file_list; p; p = p->next)
unlink (p->name);
}
int
main (void)
{
…
if (signal (SIGINT, termination_handler) == SIG_IGN)
signal (SIGINT, SIG_IGN);
if (signal (SIGHUP, termination_handler) == SIG_IGN)
signal (SIGHUP, SIG_IGN);
if (signal (SIGTERM, termination_handler) == SIG_IGN)
signal (SIGTERM, SIG_IGN);
…
}
The main links to be aware of:
Standard Signals: https://www.gnu.org/software/libc/manual/html_node/Standard-Signals.html#Standard-Signals
Termination Signals: https://www.gnu.org/software/libc/manual/html_node/Termination-Signals.html#Termination-Signals
Basic Signal Handling, including official GCC signal() usage example: https://www.gnu.org/software/libc/manual/html_node/Basic-Signal-Handling.html#Basic-Signal-Handling
Official GCC sigaction() usage example: https://www.gnu.org/software/libc/manual/html_node/Sigaction-Function-Example.html
Signal sets, including sigemptyset() and sigfillset(); I still don't understand these exactly, but know they are important: https://www.gnu.org/software/libc/manual/html_node/Signal-Sets.html
See also:
My answer on "How to manually send any signal to any running process" and "How to trap any signal in your program" (ex: in Bash).
TutorialsPoint C++ Signal Handling [with excellent demo code]: https://www.tutorialspoint.com/cplusplus/cpp_signal_handling.htm
https://www.tutorialspoint.com/c_standard_library/signal_h.htm
To me, this below line was enough to decide:
The sigaction() function provides a
more comprehensive and reliable
mechanism for controlling signals; new
applications should use sigaction()
rather than signal()
http://pubs.opengroup.org/onlinepubs/009695399/functions/signal.html#tag_03_690_07
Whether you're starting from scratch or modifying an old program, sigaction should be the right option.
signal() is standard C, sigaction() is not.
If you're able to use either (that is, you're on a POSIX system), then use sigaction(); it's unspecified whether signal() resets the handler, meaning that to be portable you have to call signal() again inside the handler. What's worse is that there's a race: if you get two signals in quick succession, and the second is delivered before you reinstall the handler, you'll have the default action, which is probably going to be to kill your process.
sigaction(), on the other hand, is guaranteed to use “reliable” signal semantics. You need not reinstall the handler, because it will never be reset. With SA_RESTART, you can also get some system calls to automatically restart (so you don't have to manually check for EINTR).
sigaction() has more options and is reliable, so its use is encouraged.
Psst... don't tell anyone I told you this, but POSIX currently has a function bsd_signal() which acts like signal() but gives BSD semantics, which means it's reliable. Its main use is for porting old applications that assumed reliable signals, and POSIX does not recommend using it.
They're different interfaces for OS's signal facilities. One should prefer using sigaction to signal if possible as the signal() has implementation-defined (often race prone) behavior and behaves differently on Windows, OS X, Linux and other UNIX systems.
See this security note for details.
From the signal(3) man page:
DESCRIPTION
This signal() facility is a simplified interface to the more
general sigaction(2) facility.
Both invoke the same underlying facility. You should presumably not manipulate the response the a single signal with both, but mixing them shouldn't cause anything to break...
I would also suggest using sigaction() over signal() and would like to add one more point.
sigaction() gives you more options such as pid of the process that died (possible using the siginfo_t struct).
I'd use signal() since it's more portable, in theory at least. I'll vote up any commenter who can come up with a modern system that doesn't have a POSIX compatibility layer and supports signal().
Quoting from the GLIBC documentation:
It's possible to use both the signal and sigaction functions within
a single program, but you have to be careful because they can
interact in slightly strange ways.
The sigaction function specifies more information than the signal
function, so the return value from signal cannot express the full
range of sigaction possibilities. Therefore, if you use signal to
save and later reestablish an action, it may not be able to
reestablish properly a handler that was established with sigaction.
To avoid having problems as a result, always use sigaction to save
and restore a handler if your program uses sigaction at all. Since
sigaction is more general, it can properly save and reestablish any
action, regardless of whether it was established originally with
signal or sigaction.
On some systems if you establish an action with signal and then
examine it with sigaction, the handler address that you get may not
be the same as what you specified with signal. It may not even be
suitable for use as an action argument with signal. But you can rely
on using it as an argument to sigaction. This problem never happens
on the GNU system.
So, you're better off using one or the other of the mechanisms
consistently within a single program.
Portability Note: The basic signal function is a feature of ISO C,
while sigaction is part of the POSIX.1 standard. If you are
concerned about portability to non-POSIX systems, then you should
use the signal function instead.
Copyright (C) 1996-2008 Free Software Foundation, Inc.
Permission is granted to copy, distribute and/or modify this
document under the terms of the GNU Free Documentation License,
Version 1.2 or any later version published by the Free Software
Foundation; with no Invariant Sections, with no Front-Cover Texts,
and with no Back-Cover Texts. A copy of the license is included in
the section entitled "GNU Free Documentation License".
From man page signal(7)
A process-directed signal may be delivered to any
one of the threads that does not currently have the signal blocked.
If more than one of the threads has the signal unblocked, then the
kernel chooses an arbitrary thread to which to deliver the signal.
And I would say this "issue" exists for signal(2) and sigaction(2).
So be careful with signals and pthreads.
... and signal(2) seems to call sigaction(2) underneath in Linux with glibc.
I see a code illustrating how to do safe signal handling. A point I don't understand that why the signal handler calls again signal (sig, catch_alarm);. What's the reason to do that? Without it, the code works too.
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
/* This flag controls termination of the main loop. */
volatile sig_atomic_t keep_going = 1;
/* The signal handler just clears the flag and re-enables itself. */
void
catch_alarm (int sig)
{
keep_going = 0;
signal (sig, catch_alarm); // <----- ???
}
void
do_stuff (void)
{
puts ("Doing stuff while waiting for alarm....");
}
int
main (void)
{
/* Establish a handler for SIGALRM signals. */
signal (SIGALRM, catch_alarm);
/* Set an alarm to go off in a little while. */
alarm (2);
/* Check the flag once in a while to see when to quit. */
while (keep_going)
do_stuff ();
return EXIT_SUCCESS;
}
The problem is that the behaviour of signal() varies across UNIX versions, and has also varied historically across different versions of Linux (quoted from Linux man). Especially:
In the original UNIX systems, when a handler that was established using
signal() was invoked by the delivery of a signal, the disposition of
the signal would be reset to SIG_DFL, and the system did not block
delivery of further instances of the signal. This is equivalent to
calling sigaction(2) with the following flags:
sa.sa_flags = SA_RESETHAND | SA_NODEFER;
So in such a system you have to call signal() again after a signal has been delivered. Because of these portability issues, the man page starts with:
The behavior of signal() varies across UNIX versions, and has also varied historically across different versions of Linux. Avoid its use:
use sigaction(2) instead. See Portability below.
To put it simply: You're wrong and the code is wrong.
Or, you assume that the signal call is superfluous - it isn't, and exists there to make the code behave correctly on platforms that use THE other allowed signal semantics.
Also, the excerpt is not about safe signal handling with signal function;
it is about how to pass an event out from a signal handler - for which there is only one portable way - by changing a variable of type volatile sig_atomic_t. To write safe portable code now, you'd use the function sigaction.
The Linux signal(2) manuals say:
The behavior of signal() varies across UNIX versions, and has also
varied historically across different versions of Linux. Avoid its
use: use sigaction(2) instead.
and
The only portable use of signal() is to set a signal's disposition to SIG_DFL or SIG_IGN.
The semantics when using signal() to establish a signal handler vary across systems (and
POSIX.1 explicitly permits this variation); do not use it for this purpose.
POSIX.1 solved the portability mess by specifying sigaction(2), which
provides explicit control of the semantics when a signal handler is
invoked; use that interface instead of signal().
And
The situation on Linux is as follows:
The kernel's signal() system call provides System V semantics.
By default, in glibc 2 and later, the signal() wrapper function does not invoke the kernel
system call. Instead, it calls sigaction(2) using flags that supply BSD semantics. This
default behavior is provided as long as a suitable feature test macro is defined:
_BSD_SOURCE on glibc 2.19 and earlier or _DEFAULT_SOURCE in glibc 2.19 and later. (By
default, these macros are defined; see feature_test_macros(7) for details.) If such a
feature test macro is not defined, then signal() provides System V semantics.
Now the question is which one is defined. If you compile with -std=c11 you will get the resetting semantics, because it doesn't set the _DEFAULT_SOURCE! And then you need to rearm the SIG_ALARM every time.
The purpose of resetting the signal in the signal handler is that some Unixen clear the handler whenever the signal is triggered. There are also other interesting edge cases - the only reason to use this function is that it is in the C standard, but its behaviour isn't well-specified there either. Never use it to set a custom signal handler.
As the code says, both of these signal calls should be frowned upon. Good modern code shouldmust use sigaction instead, for example
struct sigaction newsigfunc;
newsigfunc.sa_handler = catch_alarm;
sigemptyset(&newsigfunc.sa_mask);
newsigfunc.sa_flags = 0;
sigaction(SIGALRM, &newsigfunc, NULL);
sigaction, unlike signal, will guarantee portability here; wherever it doesn't exist, signal is likely to misbehave too...
The short answer is the original Unix implementation would reset the signal handler to it's default value after signal is received. The code here simply demonstrate this.
signal (sig, catch_alarm);
I am a novice to signal handling using c language. I am analyzing below signal handling code which extracted from specific resource.
Here is that code .
#include <stdio.h>
#include <signal.h>
void intproc();
void quitproc();
main()
{
int i;
signal(SIGINT,intproc);
signal(SIGQUIT,quitproc);
printf("Ctrl+c is disabled. Use ctrl+\\ to quit\n");
for (i=0;;i++) {
printf("In an infinite loop...\n");
sleep(200);
}
}
void intproc()
{
signal(SIGINT,intproc);
printf("You have pressed ctrl+c.\n");
}
void quitproc()
{ signal(SIGQUIT,intproc);
printf("You have pressed ctrl+\\. Now the program quits.\n");
exit(0);
}
what I want to know is why we call again Signal handler "(SIGINT,intproc)" inside intproc() function ?
I tried to run this code without that signal handler within that function ,and its also working .
This is very old code. In the old days (perhaps SunOS3, 1990-s) a signal handler was automatically uninstalled when executed. See signal(2) (difference between SysV and BSD behavior) and avoid using signal.
Carefully read signal(7) then use sigaction(2). Don't use signal(2). Care about async signal safe functions (the only ones you can call from a signal handler; you should not use printf inside a signal handler!). Consider simply setting some volatile sig_atomic_t global (or static) variable inside your signal handler (and test it outside).
Read Advanced Linux Programming which explains these things in detail.
After the function intproc has completed, the program carries on, but the signal action is restored to the default. When it receives a second SIGINT signal, the program takes the default action, which is to terminate the program.
If you want to retain the signal handler, you would need to re-establish it by calling signal again.
This is the reason you should always prefer the more robust sigaction over the signal function.
I have a registered a signal handler in my program. Upon receiving an undesired signal (SIGABRT), i call 'exit(-1)' in signal handler to exit the process. But as noticed on few ocassions, it calls exit() but fails to terminate the process.
The issue was randomly generated and I strongly suspect on execution of exit().
Can there be any reasons or cases in which the exit() can fail to terminate the process.
Thanks.
Are you calling exit() from the signal handler?
In man 7 signal, section Async-signal-safe functions you can see all the functions that are guaranteed to work when called from an signal handler:
A signal handler function must be very careful, since processing elsewhere may be interrupted at
some arbitrary point in the execution of the program. POSIX has the concept of "safe function". If
a signal interrupts the execution of an unsafe function, and handler calls an unsafe function, then
the behavior of the program is undefined.
POSIX.1-2004 (also known as POSIX.1-2001 Technical Corrigendum 2) requires an implementation to
guarantee that the following functions can be safely called inside a signal handler:
There you can see functions _Exit(), _exit() and abort(), but notably not exit(). So you should not call it from a signal handler.
The nasty thing is that even if you call an unsafe function from a signal handler (printf() any?) it will just work most of the time... but not always.
Yes, there are some circumstances, such as:
The exit() function shall first call all functions registered by atexit(), in the reverse order of their registration, except that a function is called after any previously registered functions that had already been called at the time it was registered. Each function is called as many times as it was registered. If, during the call to any such function, a call to the longjmp() function is made that would terminate the call to the registered function, the behavior is undefined.
If a function registered by a call to atexit() fails to return, the remaining registered functions shall not be called and the rest of the exit() processing shall not be completed. If exit() is called more than once, the behavior is undefined.
See the POSIX page on exit.
For more information, attach a debugger when you reach the situation and take a look at the call stack.
I had analogous problem to the one described by Madar. I needed to perform an action for every signal and quit properly. I wondered through a couple of answers to similar issues and came up with the following explanation/solution.
Explanation:
One issue is that exit() should not be used in signal handlers because it is not one of the async-signal-safe functions (see man signal-safety). This is to say that it may but is not guaranteed to work in signal handlers. As a result you would need to call _exit()/_Exit() (which are async-signal-safe). These however terminate the process instantly, without calling the atexit callbacks and static destructors. My understanding is that for some signals a bit more cleaning can be done than what those functions provide.
Solution: The solution I came up with is to register your signal handler for all signals and do any extra steps. Then you can reset to the default handler and call raise(signal_number), which is async-signal-safe, to re-send the singal and so execute the default handler.
Here is a working example that runs default handler only on SIGINT. I think this is too simple to experience the "failing" exit() if you used it in the handler. I tested similar code with an alternative stack to also handle SIGSEGV.
Note If you want this to work properly in multi-threaded context (e.g. multiple threads causing SIGSEGV at the same time) you need to take some care about synchronization. Threads share the same handler but have separate signal masking.
#include <csignal>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <unistd.h>
// The actual signal handler
extern "C" void handleSignal(int sig, siginfo_t *siginfo, void *) {
// Cannot use printf() - not async-signal-safe
// For simplicity I use a single call to write here
// though it is not guaranteed to write the whole message
// You need to wrap it in a loop
// Die only on Ctrl+C
if(sig == SIGINT) {
const char *msg = "Die\n";
write(STDERR_FILENO, msg, ::strlen(msg));
// Reset to use the default handler to do proper clean-up
// If you want to call the default handler for every singal
// You can avoid the call below by adding SA_RESETHAND to sa_flags
signal(sig, SIG_DFL);
raise(sig);
return;
}
// Here we want to handle the signal ourselves
// We have all the info available
const char *msg = "Continue\n";
write(STDERR_FILENO, msg, ::strlen(msg));
}
int main() {
// You might want to setup your own alternative stack
// eg. to handle SIGSEGV correctly
// sigaltstack() + SA_ONSTACK flag in sa_flag
// Prepare a signal action for handling any signal
struct sigaction signal_action;
signal_action.sa_sigaction = ::handleSignal;
signal_action.sa_flags = SA_SIGINFO;
::sigfillset(&signal_action.sa_mask);
// A vector of all signals that lead to process termination by default
// (see man -s 7 signal)
const int TERM_SIGNALS[] = {
SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT, SIGFPE, SIGSEGV,
SIGPIPE, SIGALRM, SIGTERM, SIGUSR1, SIGUSR2, SIGBUS, SIGPOLL,
SIGPROF, SIGSYS, SIGTRAP, SIGVTALRM, SIGXCPU, SIGXFSZ};
// Register the signal event handler for every terminating signal
for (auto sig : TERM_SIGNALS) {
::sigaction(sig, &signal_action, 0);
}
while(true);
return 0;
}
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
What is the difference between sigaction and signal?
It seems to me that both of them can be used to register a callback for a specific signal.
How do you choose which one to use?
TLPI
UNIX systems provide two ways of
changing the disposition of a signal:
signal() and sigaction(). The
sigaction() system call is an
alternative to signal() for setting
the disposition of a signal. Although
sigaction() is somewhat more complex
to use than signal(), in return it
provides greater flexibility.
sigaction is also more portable than signal. Also, with sigaction you can specify signal handlers that receive additional arguments (sa_sigaction versus sa_handler).
/* can be installed by signal / sigaction */
void(*) (int);
/* can be installed by sigaction only */
void(*) (int, siginfo_t *, void *);
From my point of view, the difference (except interface :) and portability) is in behavior after signal is caught:
If the disposition is set to a function, then first either the disposition is reset to SIG_DFL, or the signal is blocked (see Portability below), and then handler is called with argument signum. If invocation of the handler caused the signal to be blocked, then the signal is unblocked upon return from the handler.
And, also I'd like to repeat the same as the man page says:
The behavior of signal() varies across Unix versions, and has also varied historically across different versions of Linux. Avoid its use: use sigaction(2) instead.