[
Date Prev][
Date Next][
Thread Prev][
Thread Next][
Date Index][
Thread Index]
Re: setjmp/longjmp vs 754R throw exception
This will be my last attempt to explain the issues for now, as this
thread is going round in circles.
David Hough 754R work <754r@xxxxxxxxxxx> wrote:
See http://en.wikipedia.org/wiki/Longjmp
for a brief discussion of setjmp/longjmp. It seems to raise the
same implementation issues as 754R throw exception: ...
Let's ignore the inaccuracies in that - in particular, the references to
signalling are true but misleading, and the section in the C rationale
is just plain wrong. The fact is that both Michel and I probably have
more, and MUCH wider, experience than the authors of that article.
But I don't see how a programming environment that handles programs with
setjmp/longjmp is going to have much more trouble handling 754R throw.
...
In fact, 754R throw can be implemented with setjmp/longjmp (or perhaps
better with something like sigsetjmp/siglongjmp) if the alternate
handlings are stored in a table (or perhaps a stack) and exception
detection is done synchronously with flags at the end of the alternate
exception block. That might be the least inefficient solution on
systems which make asynchronous signaling expensive.
Please. For the Nth time - it is not what you do with the exception
once you have caught it - it is the catching it in the first place.
longjmp is a SYNCHRONOUS, ORDINARY function call.
In fact, many languages don't have setjmp, or place draconian
restrictions on it, for many and good reasons. But the difference
between setjmp/longjmp, throw or global flags is primarily a compiler
and performance one, not a hardware-interface one - and you ARE right
that it doesn't make much difference which you use.
Obviously, if you already have IEEE 754 flag support, they can trivially
be turned into throws by inserting some code to set and test the flags
at the start and end of the try/catch block. That never was disputed.
But I think the design intent is that the hardware provide an efficient
way to regain local control after an exception.
That is one of the examples where the IEEE 754 design team did not
consult with a representative range of hardware architects. It can't
be done, compatibly with performance, as 50 years of experience has
shown. It's not so much the principles of IEEE 754 that are the
problem as the details.
There ARE designs that could be implemented a LOT more efficiently
(though they would still have an impact), but the IEEE 754 model is not
one of them.
Even "terminate with message" is just an implicit longjmp far enough back
to an environment that knows how to clean up and continue - formerly the
job control language interpreter, now perhaps a shell.
PLEASE, take note of what Michel and I say. At a theoretical level,
that is true. At a practical one, it is totally false.
The point is that there is usually a level at which the 'operating
system' sets up a 'virtual machine' in which to run the application.
On some of the excellent capability systems, an application environment
was a true virtual machine, but a POSIX-style process environment is
an approximation, and a zOS job/session is only vaguely like that.
But almost all systems have some such heavyweight boundary.
Now, terminating one of those can be done cleanly, almost irrespective
of what has gone wrong. But terminating any sub-unit and resuming its
'parent' is very often fiendish to implement, unreliable or (usually)
both. And it is the FORMER that "Terminate with message" specifies,
and the LATTER which Annex E 'non-resumable' handling does.
As Michel says, terminating the 'virtual machine' is the only thing
that can be done on systems with imprecise exceptions and no trap
barriers accessible to applications code. But it is ALSO the only
thing that can be done without compromising the performance of the
application, even on systems that DO have them.
With threads,
child processes, parent processes, command shells, the idea of "far enough
back" is less definite than it used to be.
Not at all. It never was. With 370 systems alone, CICS, GUTS, MTS, MVS,
VM, CMS and TSO introduced enough indefiniteness to make POSIX process
and thread handling look simple.
Vincent Lefevre <vincent@xxxxxxxxxx>
And, as you say, setting the flag is not the problem. It is when
the handler is called to set it that is.
But exceptions shouldn't occur very often (except the "inexact" one,
but one usually doesn't want to trap it). Or there's a problem in
your program.
That isn't the point. The cost is caused by the number of blocks that
POTENTIALLY might trap exceptions, and the number of transfers over
their boundaries. Whether any exceptions are actually generated is
irrelevant. And THAT is one of the reasons that IEEE 754 is so
incompatible with performance on modern systems.
Note that, inter alia, every such boundary prevents any code that
might set or test a flag from being moved across it.
Also, that is not the case when NaNs are used as missing value indicators,
which is one of the many reasons to not have a max(NaN,1.23) = 1.23
operation.
Regards,
Nick Maclaren,
University of Cambridge Computing Service,
New Museums Site, Pembroke Street, Cambridge CB2 3QH, England.
Email: nmm1@xxxxxxxxx
Tel.: +44 1223 334761 Fax: +44 1223 334679