Have a question regarding the interruption of a running process that listens to signals. Below is my handler. SIGHUP is used for reloading my config file, SIGCHLD is used to waitpid with nohang on a process it spawns and the others to terminate the process.
void sig_handler( int sig, siginfo_t *siginfo, void *ucontext )
{
if ( sig == SIGHUP ) {
reload = 1;
} else if( sig == SIGCHLD) {
// TODO
} else if ( sig == SIGTERM || sig == SIGKILL || sig == SIGINT ) {
done = 1;
}
}
do {
if(reload) {
// opening files, doing file descriptor stuff
... // processing...
**SIHUP OCCURS! WHAT HAPPENS?** <<<<<<<<<<< Line: 505 <<<<<<<<<<<<<<<<<<
... // processing...
}
} while(!done);
My current understanding of signals:
signal occurs
complete current operation on line 505. ie: open("t.txt");
run signal handler code to completion
return to line 505 and continue
What I am worried about:
signal occurs
break out of current code
run signal handler code to completion
continue from break out code
Questions:
Should I enhance my code to block SIGHUP, SIGTERM, SIGCHLD while reloading the config so that I don't have unstable code if a signal occurs? Or is that over-design? (Assuming it doesn't resume after)
Say I am in the signal handler for a SIGHUP but then a SIGHUP signal occurs, what happens? (I assume it queues them and runs the handler twice)
Thanks!
Actually, if a signal occurs, your current operation isn't necessarily going to finish before the signal handler is called. However, upon completion of the signal handler, your code resumes from exactly where it was when the signal interrupted. And since all your signal handler does is set a flag variable, there's no effect on the code that currently in middle of whatever else it's doing.
Answers:
Why bother? Your code does resume after, and any properly designed signal handler isn't going to destabilize the code.
Documentation seems to indicate that the handling of the second signal will be deferred until the first handler completes. See this question for details.
Related
I'm attempting to free a bit of memory if (^C) signal is called. I haven't been successful using an 'if' statement. I'm probably ignorant of what is really going on, but I could really use some help on this one.
while ((line = readline(prompt))) {
if (signal(SIGINT, sigintHandler) == SIG_IGN){
free(line); //Trying to execute statement
continue;
}
You call signal once before your loop to install the signal handler. The signal handler itself will be executed when the signal is received.
volatile sig_atomic_t interrupt_flag_set = 0;
void sigintHandler( int sig )
{
interrupt_flag_set = 1;
}
/**
* Save the original interrupt handler in case you need to
* restore it later.
*/
void (*oldhandler)(int) = signal( SIGINT, sigintHandler );
...
while( (line = readline( prompt )) )
{
if ( interrupt_flag_set )
{
// process interrupt
}
else
{
// process line normally
}
}
...
/**
* restore the original interrupt handler.
*/
signal( SIGINT, oldhandler );
If you intend your signal handler to catch signals originating from the operating environment (i.e., users hitting Ctrl-C or timers expiring or something like that), then your signal handlers shouldn't do much more than set a flag. Calling library functions other than abort, _Exit, quick_exit, or signal with the received signal value leads to undefined behavior.
I can tell you from personal experience that calling printf from a signal handler is bad juju. I worked on a program that periodically wrote to an Access database. There was a signal handler that was supposed to write a message to standard output, but when triggered it wound up writing over the .mdb file, hosing the database beyond repair.
I want my program to run in a loop until it receives an alarm signal, in the meantime I want to run some code every time it receives an interrupt signal.
The following almost works:
bool volatile waiting = true;
bool volatile interrupted = false;
void catch_interrupt(int x)
{
interrupted = true;
}
void catch_alarm(int x)
{
waiting = false;
}
void alive()
{
signal(SIGINT, catch_interrupt);
signal(SIGALRM, catch_alarm);
alarm(10);
while (waiting)
{
if (interrupted)
{
printf("interrupted\n");
interrupted = false;
}
}
printf("done\n");
}
The problem is that it only works for the first interrupt signal. The second interrupt kills the program (without printing "done") regardless.
So the output I see is
^Cinterrupted
^C
when I want to see
^Cinterrupted
^Cinterrupted
done
Do not use signal() to install custom signal handlers, as its behavior in that case varies across implementations. In particular, on some systems, if signal() is used to set a custom signal handler for a given signal, then that signal's disposition is reset when the signal is received. That's what you seem to be observing, but you cannot portably rely on it.
Instead, install signal handlers via sigaction(). Among other things, it has a mechanism for specifying whether the handler should be reset upon receipt of the signal.
Signal handlers set with signal() are disarmed when the signal handler is called in response to a signal. You have to rearm the signals each time:
void catch_interrupt(int x)
{
interrupted = true;
signal(SIGINT, catch_interrupt);
}
void catch_alarm(int x)
{
waiting = false;
signal(SIGALRM, catch_alarm);
}
Yes, that means there is a small window of vulnerability when the first signal has been handled but the handler has not yet been reinstated when a second signal will cause the program to react as if no signal handler is installed (because no signal handler is installed).
I want to simulate a game server that should continuously send and receive signals with its parent. The scenario is as follows:
Parent sends signal to game.
Game catches the signal and sends a signal to the parent.
Parent catches the signal and sends again a signal to game.
and so on...
The problem is that the stops receiving or sending after the first lap:
static int game_s;
void game()
{
printf("game\n");
signal(SIGUSR1,game);
sleep(1);
kill(getppid(),SIGUSR1);
pause();
}
void parent()
{
printf("parent\n");
signal(SIGUSR1,parent);
sleep(1);
kill(game_s,SIGUSR1);
pause();
}
void main()
{
game_s = fork();
if(game_s>0)
{
signal(SIGUSR1,parent);
sleep(1);
kill(game_s,SIGUSR1);
pause();
}
else
{
signal(SIGUSR1,game);
pause();
}
}
The output is the following:
game
parent
Why it stopped here? Shouldn't the game server catch parent's signal and print "game" again...
By default the reception of a specific signal is blocked from the moment a process received this specific signal until the related signal handler had been left.
From man 3 signal:
void (*signal(int sig, void (*func)(int)))(int);
[...]
When a signal occurs, and func points to a function, it is implementation-defined whether the equivalent of a:
signal(sig, SIG_DFL);
is executed or the implementation prevents some implementation-defined set of signals (at least including sig) from occurring until the current signal handling has completed.
To change this behaviour establish the signal handling via sigaction() instead of signal() (which one should do any ways for portability reasons).
sigaction() takes a struct sigaction. The member sa_flags of the latter should have SA_NODEFER set.
From Linux' man 2 sigaction:
SA_NODEFER
Do not prevent the signal from being received from within its own signal handler. This flag is meaningful only when establishing a signal handler.
POSIX words this differently:
SA_NODEFER
If set and sig is caught, sig shall not be added to the
thread's signal mask on entry to the signal handler
unless it is included in sa_mask. Otherwise, sig shall
always be added to the thread's signal mask on entry to
the signal handler.
Be aware that each signal handler gets it's own stack allocated each time it gets invoked, so sooner or later this recursive ping-pong ends up in an out-of-memory condition.
Use message queues, or shared memory to do this. As stated above, this will eventually run out of memory and it will crash.
I currently have a program I have written in C on a server that has an infinite loop that processes information, each loop takes about 5 minutes to complete. I would like to have the following functionality in a shell script:
Terminate C program
Make source
Run program
The problem is, I don't know how to tell my C program to exit without doing something like ctrl+c, I would rather it finished processing the information it is currently working on before terminating itself.
The POSIX standard way to tell a process to finish its business and exit cleanly is to send it a SIGTERM signal. Depending on your application it may or may not be appropriate to exit on SIGINT, which is meant to interrupt a process, not terminate it. (Control-c sends SIGINT.)
Try putting a flag in your tight loop; check the flag at a time when it is easy to exit, but still frequently enough to exit promptly. In your case, receipt of a SIGTERM might put a message on the system log right away, then promise to exit within the next 5 minutes.
Your signal handler will look like this:
static int signalled; // if nonzero, what signal have we been sent?
static void SignalHandler(int signum) {
signalled = signum;
}
I check the global static variable signalled after every I/O operation, which means many times per second.
Here's my code to catch and restore signals:
static __sighandler_t sh, si, st;
static void catch_signals(void) {
if ((sh = signal(SIGHUP, SignalHandler)) == SIG_IGN) signal(SIGHUP, SIG_IGN);
if ((si = signal(SIGINT, SignalHandler)) == SIG_IGN) signal(SIGINT, SIG_IGN);
if ((st = signal(SIGTERM, SignalHandler)) == SIG_IGN) signal(SIGTERM, SIG_IGN);
signalled = 0;
}
static void restore_signals(void) {
signal(SIGHUP, sh);
signal(SIGINT, si);
signal(SIGTERM, st);
}
(This code is from a library, so I'm being extra careful to leave things the way I found them.)
Bonus trick: when time expires (this is a TV recording library), the timer just sets signalled = SIGTERM, and the same logic is used to exit the recorder normally.
like ctrl+c, I would rather it finished processing the information it
is currently working on before terminating itsel
Establish a signal handler for SIGINT or whatever you want and do your cleanup after you receive it. You shouldn't do the cleanup in the handler itself however.
volatile sig_atomic_t do_cleanup = 0;
void handler(int sig)
{
do_cleanup = 1;
}
Then in your main loop you just have to test do_cleanup and exit when you please. You must also be careful in properly treating EINTR errors if you're not already doing so.
Here is how to send signal from shell:
http://bash.cyberciti.biz/guide/Sending_signal_to_Processes
or simply man kill
Here is how to react to signal:
http://www.cs.cf.ac.uk/Dave/C/node24.html#SECTION002400000000000000000
I was wondering if it is possible to be interrupted by a signal when my program is handling other signal at the same time, I tried to simulate it with:
#include<signal.h>
#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
#include<sys/wait.h>
#include<string.h>
void sig_output()
{
sigset_t set;
sigprocmask(0,NULL,&set);
printf("currently blocking:");
if (sigismember(&set,SIGUSR1))
printf("\nSIGUSR1");
if(sigismember(&set,SIGUSR2))
printf("\nSIGUSR2");
printf("\n");
return ;
}
void sig_handler(int sig)
{
raise(SIGUSR1);
printf("start\n");
if (sig==SIGUSR1)
printf("SIGUSR1\n");
else if (sig==SIGUSR2)
printf("SIGUSR2\n");
printf("end\n");
return ;
}
void other_sig_handler(int sig)
{
printf("start - other\n");
if (sig==SIGUSR1)
printf("SIGUSR1\n");
else if (sig==SIGUSR2)
printf("SIGUSR2\n");
printf("end - other\n");
return ;
}
int main()
{
sig_output();
struct sigaction a;
a.sa_handler=sig_handler;
a.sa_flags=0;
sigset_t set,old;
//blocking SIGUSR1,SIGUSR2
sigemptyset(&set);
sigaddset(&set,SIGUSR1);
sigaddset(&set,SIGUSR2);
printf("blocking SIGUSR1, SIGUSR2\n");
sigprocmask(SIG_SETMASK,&set,&old);
sig_output();
//adding handles for SIGUSR1,SIGUSR2
sigemptyset(&(a.sa_mask));
sigaction(SIGUSR1,&a,NULL);
a.sa_handler=other_sig_handler;
sigaction(SIGUSR2,&a,NULL);
printf("poczatek wysylania \n");
raise(SIGUSR1);
raise(SIGUSR2);
raise(SIGUSR1);
printf("using sigsuspend\n");
sigsuspend(&old);
printf("end of program\n");
return 0;
}
and everytime I run this program I get
currently blocking:
blocking SIGUSR1, SIGUSR2
currently blocking:
SIGUSR1
SIGUSR2
raising
using sigsuspend
start - other
SIGUSR2
end - other
start
SIGUSR1
end
end of program
is it always like that?
Quoting the sigaction(2) manpage:
Signal routines normally execute with the signal that caused their
invocation blocked, but other signals may yet occur. A global signal mask
defines the set of signals currently blocked from delivery to a process.
The signal mask for a process is initialized from that of its parent
(normally empty). It may be changed with a sigprocmask(2) call, or when
a signal is delivered to the process.
You can control whether the signal is automatically blocked in its signal handler with the SA_NODEFER flag.
The order in which these particular pending signals are delivered is not, as far as I know, defined. However, signals are (mostly; there's an exception for SIGCLD, which is traditionally done by "cheating") "non-queueing", except for real-time signals. The non-queuing aspect means that if you have signal X blocked, and then raise it twice (as you do above for SIGUSR1), you only get it delivered once.
The only ordering documented on at least one system (MacOS) is:
If multiple signals are ready to be delivered at the same time, any signals that
could be caused by traps are delivered first.
(These are things like SIGSEGV and SIGBUS.) In general, you can control the order of delivery by use of the signal blocking masks: unblock any particular signal(s) at some point and those are the ones that can be delivered at that point.
If you do not set SA_NODEFER, the blocking mask at the entry to your handler will always block whatever signal your handler is handling, so that you won't have to worry about recursion.
The special case for SIGCLD comes from System V, which originally implemented this by resetting the handler to SIG_DFL on each SIGCLD delivery. (In fact, SysV did this with all signals, effectively implementing SA_RESETHAND whether you wanted it or not.) The default action was to discard the signal, as if the handler were SIG_IGN. This of course created race conditions when multiple child processes finished before the handler could do its thing. Instead of a block/unblock model, though, the SysV folks put in a hack: at the end of your SIGCLD handler, you would call signal(SIGCLD, handler); to fix up the handler. At that point, if there were any exited children that had not yet been wait-ed for, SysV would immediately generate a new SIGCLD, and your handler would be entered recursively. This made it look as though the signals were queued, without actually queueing them.
For more on Linux signals, see (eg) http://www.kernel.org/doc/man-pages/online/pages/man7/signal.7.html.