Ad

How To Repeatedly Restart A Program Via Signal

- 1 answer

I wanted a convenient way to restart a program. I thought I could just catch a signal (USR1 in the example) and call exec.

#include <signal.h>
#include <unistd.h>
#include <stdio.h>

char* const* args;
void restart() {
    printf("restarting\n");
    execv(args[0], args);
}

int main(int argc, char* const argv[]) {
    printf("Starting\n");
    args = argv;
    signal(SIGUSR1, restart);
    raise(SIGUSR1); // could use pkill -SIGUSR1 file-name instead
    pause();
    printf("Terminated normally\n");
    return 0;
}

The above example kinda works. The output is

Starting
restarting
Starting

and then it hangs. Other signals can still be received.

I assume I'm just failing to clear the signal. The expected behavior is for program to keep restarting indefinitely.

Ad

Answer

Linux's man 2 signal explains what happens when you set a signal handler with signal. There are two possibilities:

  1. The disposition of the signal is reset to SIG_DFL, and then the handler is called. To handle this signal again, you need to re-establish the signal handler. This would have worked as you expected.

Or:

  1. The signal is blocked, and then the handler is called. When the handler returns, the signal is unblocked. If the handler doesn't return, the signal is still blocked, which is what was happening to you.

So one works with your code and the other doesn't. But which of the two applies? There is no reliable way of knowing. Posix allows both possibilities and both possibilities exist on different platforms. For this reason, the Linux manpage recommends:

The only portable use of signal() is to set a signal's disposition to SIG_DFL or SIG_IGN... [D]o not use it for [the purpose of establishing a signal handler].

POSIX.1 solved the portability mess by specifying sigaction(2), whichprovides explicit control of the semantics when a signal handler is invoked; use that interface instead of signal().

That's good advice. When you change to using sigaction, you'll probably want to go for the first option above, which requires:

sa.sa_flags = SA_RESETHAND | SA_NODEFER

That also comes from the Linux manpage, which is well worth reading in full. (Of course, the sigaction manpage is even more relevant.)

Ad
source: stackoverflow.com
Ad