What's the earliest I can register a signal handler?

Viewed 362

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?

2 Answers

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.)

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.

Related