how to exit from a signal routine

Mark Horton mark at cbnews.ATT.COM
Fri Jul 7 01:42:04 AEST 1989


Suppose you're writing an application, like ed or vi, that runs
interactively at the terminal, but when the user hits DEL, no
matter what is going on, it aborts and comes back for another
user command.  Suppose this program has to be very portable; it
must run on System V, Berkeley, ANSI, POSIX, and V7.

In the old days, you would catch SIGINT and have the signal
handler do a longjmp back to the main loop.  Another reasonable
approach was to have the signal handler just return, and the
read from the tty that was probably interrupted could check to
see if read exited with EINTR, and if so print another prompt
and go back for another command.

Then Berkeley 4.2BSD changed how signal worked, and if the handler
returned, the read would just resume.  It became accepted wisdom
among authors of highly portable programs that the longjmp approach
was the most portable method.  (Checking, this is true of 4.2BSD
and 4.3BSD, but SunOS 4.0 does it the System V way.)

Now ANSI C has decreed that you can't call longjmp, or any other
function except signal, from inside a signal handler for any signal
except those raised by abort, raise, or SIGFPE.  The reason given
for this is that you might be in the middle of calling that function
already when the interrupt comes in, and C library routine are not
required to be reentrant.  You can't call longjmp to get out of a
signal handler because maybe the code was in the middle of calling
longjmp when the signal came in.  Obscure, but they're right.  (On
the other hand, I can't see the harm in reentering longjmp, you'll
never get back to the first call.)

So where does this leave the developer?  ANSI C says the only way
to exit from a SIGINT handler is to return.  The routine is supposed
to pick up where it left off, ala 4.2BSD (although the System V
behavior of having the read return EINTR seems to be allowed too.)
Even if you pretend 4.*BSD doesn't exist, you can imagine the
complexity of checking for EINTR after every terminal read, if
you call handy stdio routines like getchar, scanf, and fgets.  (Nobody
calls gets anymore, right? :-)

Has anybody found a portable solution to this problem?  Is there
any conceivable implementation of longjmp that will have problems
when it gets called 1 1/2 times?

There is a similar problem with trying to call exit from a signal
handler.  exit flushes all stdio buffers, and you might have been
in the middle of an I/O operation when the signal came in.  This
could cause a core dump in exit!

Is this something that should be fixed in the ANSI C standard?

	Mark Horton



More information about the Comp.std.c mailing list