2

I have a program in C. I wish for it to always exit cleanly with exit code of 0 when it gets a SIGTERM. What is the earliest place I can register the signal handler? I added it at the top of my main(), but I worry it might get a sigterm just before the signal registers.

Is it possible to register a signal handler even earlier?

user7610
  • 25,267
  • 15
  • 124
  • 150
  • I tried this with the Python web server. `python -m http.server 8888 & sleep 2; kill -2 %%` the python exits with 0 and `python -m http.server 8888 & kill -2 %%` python exits with 130 because it did not have time to start handling the KeyboardInterruptException. I guess I can live with a brief period where signal is not yet working. Adjusting signal mask from the parent (as per some of the answers) is probably not worth the effort. – user7610 Feb 21 '21 at 13:48
  • Python Popen has an argument `preexec_fn`. I could create a Python startup script and use this to mask the SIGTERM as I start my program. https://docs.python.org/3/library/subprocess.html#subprocess.Popen – user7610 Feb 21 '21 at 13:53
  • Why are you worrying about getting a `SIGTERM` before the first line of `main`? Normally, a program should not need cleaning up anything that it does before the start of the function `main`. Do you have a [shared library that performs some kind of initialization](https://stackoverflow.com/questions/9759880/automatically-executed-functions-when-loading-shared-libraries) that must be cleaned up? – Andreas Wenzel Feb 21 '21 at 13:56
  • @AndreasWenzel No, not that I know of. I simply want to have an uniform behavior when my program gets SIGTERM. I want it to do a clean exit. I realized I can't do that if I get the signal too soon after startup... unless I block the signal first from the parent (as the answers suggest)... – user7610 Feb 21 '21 at 13:59
  • 1
    @user7610 This can have ultimate robustness (assuming a perfectly robutst OS kernel) if you block the signal even before `fork()`ing (then unblock it in the parent after the fork). Post-fork & pre-exec allows a window for the process to be killed in. – Petr Skocik Feb 21 '21 at 14:03

2 Answers2

4

Yes you can. Using platform specific initializers such as gcc's __attribute((constructor)). But that's hardly a robust solution.

If you wish to "to always exit cleanly with exit code of 0 when it gets a SIGTERM", then instruct the process-spawning code to start with SIGTERM blocked.

Your main can then register a signal handler and unblock SIGTERM (with sigprocmask or pthread_sigmask, at which point the signal handler will run immediately if it had been received at any point in between process creation up to the signal-unblocking call.

Essentially, it will defer the delivery of the signal up to a point where you're ready too handle it.

(Note that if you start the process with the signal ignored rather than blocked, then any instance of the signal received up to unignoring the signal will have been lost, as if they never happened. That would seem to go against your stated requirement.)

Petr Skocik
  • 58,047
  • 6
  • 95
  • 142
1

If you can switch to C++: between start of the program and main global variables are initialized. So in theory you could have code like the following that would be run before main is called.

int f() {
  signal(...);
  return 0;
}
int x = f();

But you don't have a guarantee in which order global objects are initialized, so x might not be initialized first, but last.

But coming back to your original request: the time between starting the program and main is so short, why do you want to prepare against someone sending a SIGTERM in that short time? Isn't that too unlikely to happen?

If it is possible you could change the parent to ignore SIGTERM and then fork and execve. signal man page says

A child created via fork(2) inherits a copy of its parent's signal dispositions. During an execve(2), the dispositions of handled signals are reset to the default; the dispositions of ignored signals are left unchanged.

So you could start your process ignoring SIGTERM until it sets a handler for SIGTERM.

Werner Henze
  • 16,404
  • 12
  • 44
  • 69