On Saturday 03 March 2012 10:14:26 Konstantin Belousov wrote: > On Sat, Mar 03, 2012 at 12:02:23PM +1100, Bruce Evans wrote: >> 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. > Might be, they should if talking about abstract C implementation, > but any useful Unix (U*x, probably) implementation gives much more > guarantees there.
Yes, being unspecified allows for the kernel to handle the saving and restoring and to install a default FP env for the handler. The compiler can also assume a default environment (unless FENV_ACCESS pragma is on) so it's probably necessary for the kernel to do so. >>> 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. > > longjmp() from a signal handler has very high chance of providing > wrong CPU state for anything except basic integer registers. And the signal might have interrupted a function that isn't reentrant, so you can still only call async-signal-safe functions after the longjmp. It doesn't really leave the signal handler context.
signature.asc
Description: This is a digitally signed message part.