What is the correct way to use signal handlers?
I saw the codes below from this question and was wondering why do you still need to put signal(SIGSEGV,sig_func); inside the sig_func? Wouldn't that create an unending loop when the process receives a SIGSEGV signal?
void sig_func(int sig)
{
write(1, "Caught signal 11\n", 17);
signal(SIGSEGV,sig_func);
}
int main()
{
signal(SIGSEGV,sig_func); //Install the signal handler
//Do work here
}
The signal manual says:
Finally, if the handler is set to a function sighandler then first either the handler is reset to SIG_DFL or an implementation-dependent blocking of the signal is performed and next sighandler is called with argument signum.
The repeat call to signal is used to reinstall the custom handler after it (might) have been reset to SIG_DFL.
in the example you provided, calling signal in sig_funct is useless because you have already set the signal handler in main and did not change it inside your handler.
considering your second question,no,it will not create an unending loop because signal() sets the disposition of the signal SIGSEGV to handler but do not execute it.
Related
I am working on a project involving signal-driven I/O which may end up using a signal handler created with sigaction(). My concern is that the handler might be called multiple times. In other words, it will be processing message A, when it gets interrupted by message B and start processing B, possibly causing a problem. I have seen some code on the web that uses sigprocmask to avoid this, but it appears wrong to me. For example:
void handle_signal(int sig_num)
{
sigset_t mask_set; /* used to set a signal masking set. */
sigset_t old_set; /* used to store the old mask set. */
/* re-set the signal handler again to catch_int, for next time */
signal(SIGINT, catch_int);
/* mask any further signals while we're inside the handler. */
sigfillset(&mask_set);
sigprocmask(SIG_SETMASK, &mask_set, &old_set);
.... (content handling code here) ....
/* restore the old signal mask */{{/COMMENT_FONT}*/
sigprocmask(SIG_SETMASK, &old_set, NULL);
}
This is obviously wrong because sigprocmask is not atomic with the signal. In other words, there is a window of time between when the signal handler is called and when sigprocmask is called, and the signal handler could be called a second or third time in that window, creating a race condition.
My options:
(1) Use a semaphore inside of the handler to queue any redundant calls of the handler.
(2) Write the handler to be re-entrant, so it is fine for it to be called multiple times concurrently.
(3) Some other solution?
If I go for option (2) above, can I consider a socket read queue to be thread safe? For example, let's say a socket handler gets called twice. Instance A starts reading from the socket, then it is interrupted, and Instance B starts finishes reading the packet. Will this cause A to just find the queue empty and finish up or will I be at risk for some kind of error?
If you're using sigaction to setup the signal handler then the signal that caused the handler to be triggered will by default already be blocked inside the handler.
In your code then the blocking of all signals and then the restore of the old mask is about blocking all other signals, the original signal (that triggered the handler) will be blocked until you return from the handler (or you specifically unblock it).
With sigaction you can avoid doing this block and restore in the handler by setting the sa_mask field of the struct sigaction, which is the set of signals blocked in the handler.
Further, your use of signal to "re-set" the handler is a little confusing, you call your function handle_signal then you re-set to catch_int (assuming this handler is actually handling SIGINT...
The older signal API did used to reset the signal handler back to the default each time the handler was triggered. However, by default sigaction does not do this, so you shouldn't need to "re-set" the signal handler if you're using the sigaction API. I personally would avoid mixing calls to signal and sigaction in the same program, I'd choose one and stick to it.
In conclusion, I think your concerns about sigprocmask not being atomic are unnecessary as the signal in question is already blocked, your mixed use of signal and sigaction worries me more.
Consider the following chunk of C code:
void TERMHandler(int sig){
signal (sig, SIG_DFL);
}
main() {
pid_t pid;
pid = fork()
if (pid == 0) {
signal(SIGTERM,TERMHandler);
while(1);
}
else
{
sleep(3);
kill(pid,SIGTERM);
sleep(3);
kill(pid,SIGTERM);
}
}
We create a new process and distinguish between child (pid = 0) and parent.
Can a custom handler be used for every type of signals? If so, assuming we create a custom handler, is it right that there wouldn't be any difference between all signals if I only use the signal once (or never reset the signal handler), since it would just execute my handler without considering the signal in the function?
What I'm trying to say is, is it right that:
signal(SIGTERM,CustomHandler);
signal(SIGTSTP,CustomHandler);
signal(SIGHUP,CustomHandler);
...
will execute the same code when the parent runs kill(pid, SomeSignal)?
Can a custom handler be used for every type of signals?
Yes, the same custom signal-handler function can be registered to handle different types of signals, up to and including all the signals that can be caught on the system in question. Note, however, that there may be defined signals that cannot be caught. On POSIX-conforming systems, for example, SIGKILL and SIGSTOP have this property.
If so,
assuming we create a custom handler, is it right that there wouldn't
be any difference between all signals if I only use the signal once
(or never reset the signal handler), since it would just execute my
handler without considering the signal in the function?
The signal handler function is not obligated to consider the signal number in determining what to do. It can perform the same action no matter what, or, as in your example function, it can simply pass the signal number on to some other function. You may or may not consider the latter to be a special case of the former.
Do note, however, that on a POSIX system, the sigaction() function is preferable to signal() for modifying signal dispositions. Its behavior is both more flexible and more consistent than signal()'s over various operating systems.
Can a custom handler be used for every type of signals?
Yes. You can install a custom "signal-catching" function for all signals which can be caught. (For example, SIGKILL and SIGSTOP may not be caught.)
[I]s it right that there wouldn't be any difference between all signals if I only use the signal once (or never reset the signal handler), since it would just execute my handler without considering the signal in the function?
That depends on how you code your signal catching function. The system will pass the caught signal to the function, so the same function could do something different upon catching a SIGTERM rather than a SIGHUP, for instance. If your handler ignores its sig argument and ignores the signal environment generally (masks, stacks, dispositions), then, yes, each invocation would be like any other.
The pause() function blocks until a signal arrives.
Assuming the process got a signal and pause() returned, does the signal handler will be executed before the code that follows the pause() call, or the result is unexpected?
Example:
void sigusr1_handler()
{
// .. handler code
}
void main()
{
// .. bind handler to SIGUSR1
pause(); // wait for SIGUSR1
// some more code
}
Does "some more code" will always be executed after sigusr1_handler() has finished, or there is a race condition? If so, what is the solution?
I cannot think of anything besides busy-waiting, but then the pause won't be needed at all..
Citing from the man page for pause(2):
pause() returns only when a signal was caught and the signal-catching function returned. In this case, pause() returns -1, and errno is set to EINTR.
You can be sure that your signal handler runs before some more code.
Signal handlers do not run concurrently; they interrupt the thread that handles them, and the interrupted flow only continues when the signal handler returns.
However, there may be other race conditions associated with your example; with just sparse pseudo-code and not a full explanation of your usage case, it's hard to say. For example a different signal might arrive and interrupt the pause before your signal does, and then your handler could end up running later than you expected.
There are several "right ways" to do this instead:
write a single byte to a pipe in the signal handler, and read from it in the main flow of execution.
sem_post a semaphore from the signal handler, and sem_wait in the main flow of execution.
Use sigwaitinfo or sigtimedwait instead of a signal handler.
Still use pause, but in a loop:
while(!signal_handler_finished) pause();
where signal_handler_finished has type volatile sig_atomic_t, and is set to a nonzero value in the signal handler.
I'm now learning signals in computer system and I've stuck with a problem. There is a code given below;
int i = 0;
void handler(int s) {
if(!i) kill(getpid(), SIGINT);
i++;
}
int main() {
signal(SIGINT, handler);
kill(getpid(), SIGINT);
printf("%d\n", i);
return 0;
}
And the solution says that the possible output should be 0, 1, or 2. I understand that these are possible, but why not 3, 4 or others?
For example, we send SIGINT in the main function. Handler gets SIGINT signal, and send SIGINT as it is zero. Before it proceeds to the increment code, handler might be able to listen to SIGINT signal and send SIGINT signal one more time as it is executed before the increment code (i = 0) - loops again, again - and it might print out 3, 4, 5, or even bigger numbers.
Historically, lots of details about how signals work have changed.
For instance, in the earliest variant, the processing of the signal reverted to default when the handler was called, and the handler had to re-establish itself. In this situation, sending the signal from the handler would kill the process.
Currently, it is often the case that while a handler is called for a particular signal, that signal is blocked. That means that the handler won't be called right then, but it will be called when the signal gets unblocked. Since there is no memory of how often the signal was sent, some of them may be "lost".
See POSIX <signal.h>,
Signal Concepts,
signal()
and sigaction().
This is because signals are usually blocked while delivered. So, in your example, the kill inside handler can't have effect at that place. You must wait to return from the handler to expect catching the signal again.
In theory, you can obtain 0 because it is unspecified when a signal is delivered. So, it is possible that you throw the signal in the main, and before its delivery you execute the printf.
You can get 1, because in general signal delivery occurs at the end of system call or begin or end of quantum. So in your case, just after sending the signal your return to user space and the signal is delivered, which produces the execution of the handler, incrementing i and then returning to the normal stream of execution and then prints.
You can have 2 because when returning from the handler, the signal is unblocked and then delivered for the second time. This is the more common case.
You can't have more than 2 because you set a condition for this. When i!=0 you don't throw the signal again, so it can't be thrown more than 2 times.
Beware that there is no "recursion" here...
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;
}