how to exit from a signal routine

david.f.prosser dfp at cbnewsl.ATT.COM
Sat Jul 8 00:06:02 AEST 1989


In article <7997 at cbnews.ATT.COM> mark at cbnews.ATT.COM (Mark Horton) writes:
}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.

The version of C (K&R or ANSI) is orthogonal to the operating
system.  I assume you mean portable to various different UNIX(tm)
systems, with old or new C implementations.

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

This almost always worked, but you could always interrupt at certain
points that caused subsequent code to misbehave.

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

It's more than just a nonreentrant longjmp(): it's that no library
function other than signal() is guaranteed not to be mucking around
with static data.  If you are in the middle of a stdio function,
there are windows during which data structures are inconsistent.
Short of wrapping all such critical regions with signal-preventing
code, the "no functions can be called in an asynchronous signal handler
for a portable program.

}
}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? :-)

The recommended approach is for your signal handler to set an external
volatile sig_atomic_t object and return.  The main loop should check the
value of this object at appropriate points.  The 4.*BSD behavior for
certain system calls does get in the way, unfortunately.  For such
systems, the nonportable longjmp() approach may be the only choice.

}
}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!

If you are using POSIX-based systems, you should be able to call _exit()
without any problems.  This, of course, is not highly portable--it is
generally available only on UNIX systems.

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

The only "fix" to the standard would be either to completely remove any
notion of signal handling, or to standardize on a "secure" signal
function set.  There is nothing that can be done that makes the standard
libraries signal-proof.  There were enough proponents for the
availability of some sort of asynchronous signal handling that signal
remained in the standard, despite the technical problems with any sort
of guarantees.

}
}	Mark Horton

Dave Prosser	...not an official X3J11 answer...



More information about the Comp.std.c mailing list