Kevin Brodsky wrote:
> The thing is, "the next level of the program" really is another program,
> i.e. the one that invoked it, and you are communicating via the exit
> status, so it's certainly not as explicit as re-throwing an exception in
> C++, for instance. But sure, once you are aware of this mechanism, it's
> not difficult to understand the rationale.
One shouldn't confuse exception handling with signal handling. They
are really quite different things. :-)
> Actually, IMHO, what makes it look very counter-intuitive is the fact
> that you need to first reset the signal handler for SIGINT. Of course
> this is necessary to avoid invoking the handler recursively, but it
> feels very much like a workaround.
You probably remember that signal(2) is unsafe because it does exactly
that and resets the signal handler to the default. This creates a
race condition. There is a window of time in the signal handler when
a second signal can catch the program with the default state set
before it can reset the signal handler. That is the main reason why
sigaction(2) should be used instead.
> WIFSIGNALED is true if "the child process [...] terminated due to
> the receipt of a signal that was not caught". That's not really what
> we want to know here; we want to know if the child process received
> a signal that caused it to terminate. Whether it handled SIGINT to
> clean up resources is irrelevant; what's relevant is that it
> eventually terminated as a consequence of SIGINT. Ideally, exit()ing
> from a signal handler should set a bit in the exit status expressing
> exactly this.
Well... Maybe. But how are you going to know if the program
"eventually terminated as a consequence of SIGINT" or not? And of
course then you would need a way to provide a program to do the
opposite when required.
But it has been 40 years already with the current way things are done
and it is a little late to change things now.
> I'll stop digressing, POSIX is what it is and we won't change it anyway
> ;-) For now, there's no other way to communicate with the shell, so
> that's fair enough.
I don't see how POSIX is even involved in this. Other than stopping
the proliferation of differences on different systems. Before POSIX
came along every system did this slightly differently. It was awful.
POSIX.1 simply picked BSD as the behavior to standardize upon. And
then we could stop putting #ifdef's in our code for every different
What you are seeing here is just the basic behavior of the old Unix
and BSD kernels and now every kernel that has followed since. Since
that is the common behavior among all systems the standards bodies
will mostly say, freeze on that behavior, do it the same way, don't do
it differently. Surely that is a good thing, right?
The subtleties of https://www.cons.org/cracauer/sigint.html about how
programs should behave were learned not all at once but over the
course of time.