With the following signal handler, pressing Ctrl-C
causes the handler to be called repetitively, and I don't know why:
(Warning: if you type Ctrl-C
, you'll have to use kill <pid>
to exit the program)
static void handler(int sig) {
// do something interesting
// write so I can see if I'm in an infinite loop
write(1, "A", 1);
// raise normal signal behavior
// this ensures normal signal behavior
// for example, exiting with code 130 if Ctrl-C is used
signal(sig, SIG_DFL);
raise(sig);
// re-register handler
// that way, if signal doesn't exit the program and the signal
// is sent again in the future, this handler will run again
signal(sig, handler);
}
So I know that I don't understand something about signal handlers. I assumed that only SIGCONT
would ever make it to the last line, because SIGINT
(for example), when it is raised with the default behavior (SIG_DFL
) should exit and not return.
I also know I could wrap the last line in an if statement that only does it for SIGCONT
, but I really want to know why it isn't behaving the way I expect.
This can be run by writing it to a file sigtest.c
and doing make sigtest
. Use Ctrl-C
to raise SIGINT
, and in another terminal, be prepared to do ps | grep sigtest
and then kill <pid>
.
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
static void handler(int sig) {
// do something interesting
// write so I can see if I'm in an infinite loop
write(1, "A", 1);
// raise normal signal behavior
// this ensures normal signal behavior
// for example, exiting with code 130 if Ctrl-C is used
signal(sig, SIG_DFL);
raise(sig);
// re-register handler
// that way, if signal doesn't exit the program and the signal
// is sent again in the future, this handler will run again
signal(sig, handler);
}
int main(void) {
char c;
signal(SIGINT, handler);
signal(SIGTSTP, handler);
signal(SIGCONT, handler);
printf("type 'x' and 'Enter' to exit\n");
while (1) {
c = getchar();
printf("got char: %c\n", c);
if (c == 'x') { break; }
}
}
I blanked and forgot that a signal is blocked while it is being handled. Which means that SIGINT
wouldnt' actually be raised until after the handler returns, and after I've set the action back from SIG_DFL
to my custom handler. Therefore, it is looped.
A working handler for my example looks like:
static void handler(int sig) {
if (sig == SIGCONT) {
// do something interesting
signal(sig, handler);
signal(SIGTSTP, handler);
} else {
// do something else interesting
signal(sig, SIG_DFL);
raise(sig);
}
}