In university we are currently learning about daemons and how to handle signals.
But why is the signal-handler calling signal()? In the main-method signal(...)
is already being called. So to my understanding when pkill -SIGUSR1
for example is sent to the thread the one signal(...)
call in the main-method should be sufficient in catching and delegating to the handler. Maybe someone can explain.
In our textbook there is this example:
void sighandler (int sig) {
printf ("Caught signal %d\n", sig);
signal (SIGINT, sighandler);
signal (SIGALRM, sighandler);
}
int main (int argc, char *argv [], char *envp []) {
char buffer [1024];
int len;
signal (SIGINT, sighandler);
signal (SIGALRM, sighandler);
alarm (5);
for (len = 0; len < 10; len++)
printf ("Counting %d...\n", len), sleep (1);
alarm (10);
while (1) {
len = read (0, buffer, sizeof (buffer) - 1);
if (len == -1) {
perror ("read () failed");
continue;
}
if (len == 0) {
printf ("Exiting\n");
exit (0);
}
buffer [len] = '\0';
if (!strncmp (buffer, "exit", 4))
exit (0);
write (1, buffer, strlen (buffer));
}
}
Answer
The code is re-installing the signal handlers so that subsequent SIGINTs and SIGALRMs invoke the same signal handler again.
Why? Historically, some implementations of signal()
reset the signal disposition to the default (SIG_DFL) upon invoking a user-defined signal handler, effectively making the signal handler a "one shot" affair. Some did not do this.
Thus, a common practice was to have user-defined signal handlers re-install themselves to make the handler effectively permanent. (On systems that did not reset disposition, this merely made the signal handler slightly less efficient by introducing a pointless syscall.)
sigaction()
, the successor to signal()
which was standardized in POSIX.1-1988, resolves this ambiguity by providing a flag, SA_RESETHAND, to control whether or not the handler is reset.
Aside
The commenters above are quite right: the code you are studying is a bad example.
Any use of signal()
is dubious in modern, production-quality code. That alone would not pass code review in many shops.
Even allowing signal()
, the fact that the handler is not re-installed right away, before the printf()
, is a bit odd.
printf()
is not async-signal-safe. In very simple toy programs it can be used without problems in a signal handler, but even this very example is not safe. What if the printf()
in the handler is called during the main loop's printf()
? What if that five second ALRM handler call interrupts an INT handler call?