2009-09-05
Why the Unix EINTR
semantics (probably) exist
Given the problems that the POSIX EINTR
stuff causes to various programs, one might wonder why they exist
at all. Why not make all system calls restart when signals are
delivered?
What I believe it comes down to is library safety.
Suppose that your signal handler wants to change the main flow of
the program. There are two plausible mechanisms for this: you can
immediately transfer control back to the main flow of your program with
some changes (the traditional setjmp()/longjmp()
approach), or you can
cause whatever your program is doing to unwind back to the point where
your main code can regain control and notice the changes.
The problem with an immediate transfer of control is that if your program happened to be in a library at the time, you've preempted the library at an arbitrary time (and you probably expect to be able to keep calling the library). It's unreasonable (and in fact impossible) for libraries to be arbitrarily preemptible and re-enterable, so that it's always safe for you to jump from your signal handler to your main program and carry on as if nothing had happened.
In other words, libraries must have some way of unwinding and cleaning up their state, so that it's safe to call them again.
In a different environment, this would be an exception system. But C and
Unix don't have those, so the kernel has to explicitly return control to
the normal user-level code while making it visible what's happening. In
other words, it has to interrupt system calls and return EINTR
. At
that point, a smart library can do something sensible and a dumb library
is likely to return to the main program with an error, which at least
lets the main program regain control and do whatever it wants.
A lot of programs don't need this, though, because they mostly or
entirely use signals for temporary preemption; their signal handlers
report things, or cause data saves, or whatever. For these programs,
EINTR
is a pain in the rear and BSD signal semantics are a blessing.
(Mind you, many of these programs are living in sin because they call
library routines like fprintf()
from inside signal handlers.)