svn commit: r232275 - in head/sys: amd64/include i386/include pc98/include x86/include

Bruce Evans brde at optusnet.com.au
Sat Mar 3 01:02:27 UTC 2012


On Fri, 2 Mar 2012, Tijl Coosemans wrote:

> On Friday 02 March 2012 05:11:21 Bruce Evans wrote:
[... Lots about complications for longjmp() from a signal handler]

> Thanks, that was quite informative. C11 does say something about the
> FP env and signals now though:
>
> ``When the processing of the abstract machine is interrupted by receipt
> of a signal, the values of objects that are neither lock-free atomic
> objects nor of type volatile sig_atomic_t are unspecified, as is the
> state of the floating-point environment. The value of any object
> modified by the handler that is neither a lock-free atomic object nor
> of type volatile sig_atomic_t becomes indeterminate when the handler
> exits, as does the state of the floating-point environment if it is
> modified by the handler and not restored to its original state.''

Interesting.  This is almost exactly the same as my justification for
not caring about old signal handlers getting a dirty FP state.  Since
signal handlers can't do anything with static objects except write
to volatile sig_atomic_t ones, they can't do anything useful with FP.
But old standards seem to allow them to do silly things like calculate
pi to a billion decimal places and store the result encoded in an
array of about 1 billion sig_atomic_t's, or better yet, calculate
2.0 + 2.0 and store the result in a smaller array of sig_atomic_t's.

Oops, the above doesn't clearly say of the unspecified state is for
the signal handler, or after the signal handler returns, or both.  The
second sentence it only clearly says that certain objects and state
become indeterminate after bad behaviour by signal handlers.  But we
want longjmp()s from signal handlers to be usually not bad behaviour.
The above at least allows them to work right.  Maybe longjmp() can
determine if it is invoked in a signal handler and do the right thing
then.  longjmp()s for machines that are too complicated for me have
to do sophisticated stack unwinding.  This might require even more
sophisticated unwinding for signal handlers.  This reminds me that
POSIX (?) weasels out of some of the complications by only requiring
a single level of nested signal handlers to work.

> This means a signal handler must not rely on the state of the FP env.
> It may install its own FP env if needed (e.g. FE_DFL_ENV), but then it
> must restore the original before returning. This allows for the
> rounding mode to be silently modified for integer conversions for
> instance.

Well, I think the kernel can't trust the signal handler to do that.  It
also can't trust the compiler.  The compiler can reasonably use FP for
anything it wants if this is (the compiler thinks) transparent to the
abstract machine, but the compiler can't know when the code is for a
signal handler without complicated directives.  Then on x86, integer
operations may use the same SSE registers (although perhaps not mxcsr)
as FP uses, and again the compiler can't reasonably know when not to
do this.  So the kernel must restore at least the shared registers,
and for SSE this means restoring using f*rstor which handles the whole
state at no extra cost.

So the interesting points for signal handlers move to:
- should signal handlers have to initialize their own state if they want
   to use FP explicitly?  I think they should.
- should signal handlers have to initialize their own state if they want
   to use FP or shared registers implicitly (because the compiler wants to)?
   No.  The kernel must handle this transparently, much like it does now,
   and I think this makes the previous case work transparently too.  The
   kernel tries to do this lazily, but it doesn't do this very well (it
   copies the state several times in sendsig() and sigreturn()).
- when the signal handler wants to modify the interrupted state, how does
   it do this?  There is minimal support for this.  The easiest way to
   modify it is to modify the current state and then longjmp() instead of
   returning.
- how can signal handlers and debuggers even see the interrupted state?
   gdb has less clue about this than it did 20 years ago.  Users can
   probably use debuggers to follow various pointers to the saved state
   if they know more about this than signal handlers and debuggers.

> If longjmp is not supposed to change the FP env then, when called from
> a signal handler, either the signal handler must install a proper FP
> env before calling longjmp or a proper FP env must be installed after
> the target setjmp call. Otherwise the FP env is unspecified.

Better handle the usual case right like it used to be, without the
signal handler having to do anything, by always saving a minimal
environment in setjmp(), but now only restoring it for longjmp() in
signal handlers.  The minimal environment doesn't include any normal
register on at least amd64 and i386 (except for i387 it includes the
stack and the tags -- these must be empty on return from any function
call).

Again there is a problem with transparent use of FP or SSE by the
compiler.  An average SIGINT handler that doesn't want to do any
explicit FP and just wants to longjmp() back to the main loop can't
be expected to understand this stuff better than standards, kernels
and compilers and have the complications neccessary to fix up the FP
state after the compiler has transparently (it thinks) used FP or SSE.

Bruce


More information about the svn-src-all mailing list