Topic: Throwing an exception from within a si


Author: clamage@Eng.Sun.COM (Steve Clamage)
Date: 1996/01/20
Raw View
In article k04@wcap.centerline.com, chase@centerline.com (David Chase) writes:
>In article mca@engnews1.Eng.Sun.COM, clamage@Eng.Sun.COM (Steve Clamage)
>writes:
>> Suppose that function entry and exit are not atomic operations, which is
>> the case on all systems supporting C++ that I am aware of. The "critical
>> structure" is the stack frame. If asynchronous interrupts can occur, and
>> if you are going to require well-defined exception behavior from signal
>> handlers, then you must lock the entirety of every function preamble and
>> postamble. (You cannot know that an external signal won't occur.) That
>> requirement not only slows down function calls, it adds to interrupt
>> latency.
>
>As near as I can tell, the best way to do this is to slightly enhance a
>PC-range-based exception-handling specification.  I was pushing for
>this for the Sparc V9 ABI when I worked at Sun, but it was tough
>slogging.  [ explanation of how to do it deleted ]

>> What we put in the language standard is binding on all implementations. We
>> try to specify things that can be implemented efficiently on any likely
>> system. In addition, we try to specify features so that they have no cost
>> (or nearly no cost) if you don't use them. IMHO, guarantees about what you
>> can do in an asynchronous signal handler don't meet those criteria for
>> inclusion in the C++ standard.
>
>I think I've just described a way to do this that is efficient on any
>likely system, and that has no runtime cost if you don't use it. ...

>An additional stunt is simply to have your exception-handler recognize
>standard function pre and post-ambles, or standard phases of activation
>record construction, and avoid the need for additional code. ...

I'm more than willing to assume your implementation technique has merit.
Yet didn't you say you were not able to get it approved? So what
is a C++ implementor to do if the only reasonable implementation
technique violates the platform ABI?

I have longer experience with non-RISC implementations than with RISC
implementations. It is common for non-RISC implemenations not to have
a recognizable function preamble or postamble. There are not just two or
three possible instruction sequences making up function entry and exit --
there are dozens or even hundreds of possible sequences. If you standardize
on recognizeable entry and exit sequences you take a noticeable performance
hit, particularly on popular benchmark programs.

I want to say again that a criterion for a feature in the standard is not
whether you can somehow implement it on some systems. The criterion is more
like whether you can implement it with appropriate efficiency on all
systems and not adversely affect programs that don't use the feature.
If a feature does not meet this criterion, it has to be widely beneficial
to justify its inclusion.
---
Steve Clamage, stephen.clamage@eng.sun.com
---
[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]





Author: thp@cs.ucr.edu (Tom Payne)
Date: 1996/01/20
Raw View
Dick Menninger (Dick.Menninger@daytonoh.attgis.com) wrote:
:
: > ==========Steve Clamage, 1/16/96==========
:
: > In article 22h@galaxy.ucr.edu, thp@cs.ucr.edu (Tom Payne) writes:
:
: > >Implicit in a qestion of what the Standard says are the related
: > >questions of what it should say and why --- why shouldn't signal
: > >handlers be allowed to throw exceptions?  (The question seems both
: > >interesting and appropriate.)
:
: > [...]
:
: Signal handlers are analogous to interrupt handlers at
: application level.  They form separate asynchronous
: processing that may communicate to the rest of the
: application but are really a separate thread.  How they
: communicate to the rest of the application is colored
: thoroughly by their nature.  The problem in thinking
: about exceptions in signal handlers seems to be that
: everybody is treating them as part of the thread they interrupt.
: That leads you down the path to oblivion.  They should
: be seen as a separate thread of execution.  An exception
: does not go back through the special save boundary.
: To do that would be like an exception in one thread
: continuing through another threads stack.  When you
: look at a signal handler as a threadlike thing that happens
: to preempt another thread, you start making sensible
: decisions that allow a signal handler to do that little
: more that is probably necessary.  Since exceptions
: are required at rather basic levels now, precluding
: them is very unrealistic.

Good analysis, but I'm unclear about the conclusion.  Functions called
by signal handlers should be allowed to throw exceptions.  If,
however, the signal handler itself throws an exception or fails to
catch one thrown to it, then the situation seems analogous to the base
function of a thread throwing an exception or failing to catch one
thrown to it.  Shouldn't we consider that a bug?

Tom Payne (thp@cs.ucr.edu)
---
[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]





Author: thp@cs.ucr.edu (Tom Payne)
Date: 1996/01/22
Raw View
Steve Clamage (clamage@Eng.Sun.COM) wrote:
:
: Suppose that function entry and exit are not atomic operations, which is
: the case on all systems supporting C++ that I am aware of. The "critical
: structure" is the stack frame. If asynchronous interrupts can occur, and
: if you are going to require well-defined exception behavior from signal
: handlers, then you must lock the entirety of every function preamble and
: postamble. (You cannot know that an external signal won't occur.) That

If signal blocking and postponement is implemented with a couple of flags
in the programs static area, we are looking at two writes and a test
at the typical call and return.

: requirement not only slows down function calls, it adds to interrupt
: latency.

: How expensive is it to lock and unlock every function entry and exit?
: On some systems it is cheap. On others it is expensive. Considering that

I think that has to do with efficiency of the signal-blocking aspects
of the signal handling library rather than an inherent limitation of
the underlying architecture.

: a characteristic of OO programs is having many small functions, requiring
: these locks could have a dramatic impact on program performance, even
: for programs that don't want to throw exceptions from signal handlers.

If we use another flag to tell whether an exception-throwing handler
has been installed, then we can bypass the signal blocking when the
feature isn't used.  (Applications that can't tolerate the increased
signal latency shouldn't throw exceptions from signal handlers.)

: What we put in the language standard is binding on all implementations. We
: try to specify things that can be implemented efficiently on any likely
: system. In addition, we try to specify features so that they have no cost
: (or nearly no cost) if you don't use them. IMHO, guarantees about what you

Agreed!!

: can do in an asynchronous signal handler don't meet those criteria for
: inclusion in the C++ standard.

That's a rather broad conclusion, given the discussion so far.
Perhaps the fist implementation that comes to mind (for implementing
exception throwing from signal handlers) doesn't meet those criteria,
even with the patches suggested above.  Still, to dismiss the
possibility of an efficient implementation for this and/or other
asynchornous capabilities seems premature.

Tom Payne (thp@cs.ucr.edu)
---
[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]





Author: bill@amber.ssd.hcsc.com (Bill Leonard)
Date: 1996/01/22
Raw View
In article <4dos4l$ra9@engnews1.Eng.Sun.COM>, clamage@Eng.Sun.COM (Steve Clamage) writes:
> I have longer experience with non-RISC implementations than with RISC
> implementations. It is common for non-RISC implemenations not to have
> a recognizable function preamble or postamble. There are not just two or
> three possible instruction sequences making up function entry and exit --
> there are dozens or even hundreds of possible sequences. If you standardize
> on recognizeable entry and exit sequences you take a noticeable performance
> hit, particularly on popular benchmark programs.

I have quite a bit of experience designing and implementing compilers and
programming tools (such as debuggers) on both RISC and non-RISC
architectures.  What Steve says is correct, but more importantly, it is not
limited to non-RISC architectures.  RISC compilers are becoming ever more
aggressive at optimization, and one of the areas that gets increasing
attention is function entry and exit.

Even without optimization, function entry and exit on many RISC machines is
not limited to a few recognizeable sequence of instructions.  Register
saving and restoring, for instance, can add lots of instructions to the
preamble or postamble.

But when you factor in optimizations such as sinking register saves and
hoisting register restores, moving user instructions into the preamble,
speculative execution of instructions, and so forth, the number of possible
sequences is infinite.

Now weigh against that the benefit, if there is any, of allowing an
exception to propagate out of a signal handler.  Does it buy you enough to
*require* RISC compilers to throw away huge performance gains?  Not in my
opinion.

--
Bill Leonard
Harris Computer Systems Corporation
2101 W. Cypress Creek Road
Fort Lauderdale, FL  33309
Bill.Leonard@mail.hcsc.com

These opinions and statements are my own and do not necessarily reflect the
opinions or positions of Harris Computer Systems Corporation.

------------------------------------------------------------------------------
There's something wrong with an industry in which amazement is a common
reaction to things going right.

"Hard work never scared me.  Oh, sure, it has startled me from a distance."
                                                       -- Professor Fishhawk
------------------------------------------------------------------------------
---
[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]





Author: chase@centerline.com (David Chase)
Date: 1996/01/22
Raw View
Ugh.  My earlier reply may have been less temperate than I like.
The point I wish to make is that there is no calling-convention-
technical reason making it impossible to implement asynchronous
exception handling on most machines.  The costs vary, but are
usually low, or can be engineered to be low (if you insist on
shrink-wrapping the register saves for every single procedure
that you compile, the costs will be unreasonable, but the obvious
engineering choice is to only shrink-wrap where it is profitable,
and pay the table size cost there).

Furthermore, there are reasons to like asynchronous exceptions.
Sometimes, things are asynchronous.  Timers expire.  People chop
network connections with backhoes.  Printers catch fire.  One
person that I worked alongside, if not with, in two different
jobs, chewed my ear off (even though I agreed with him) on the
necessity for asynchronous exception-handling.

However, there are some language problems with asynchronous
exception-handling.  At the machine level, async exceptions can be
dealt with in an abort/commit/finish-quickly style that always gets you
to a defined state.  To properly deal with asynchronous exceptions, the
abort/commit/finish style has to percolate upward from the machine
level, through every assignment statement, and through every
interface.  With very careful design of the constructor and destructor
interaction, together with careful specification of both concurrent
semantics and pseudo-atomic semantics (pseudo-atomic means atomic with
respect to ones' own interrupt routines, but not atomic with respect to
another thread), this can happen.  Essentially, every operation either
finishes (commits) with its defined semantics, or else it throws an
exception (aborts) and backs out the operation (transaction) to a
well-defined (preferably initial, or an isomorphism of initial) state.
Furthermore, one thread is not allowed to observe another thread's
half-completed operations (implicit in this sentence is some tremendous
handwaving about transaction granularity, since a larger transaction
may consist of a number of smaller ones, some of which may succeed
before the larger one fails, or vice-versa).  Such a language might
be really fun (perhaps difficult, but still fun) to program in, because
if the support for this style worked properly, it should lead to more
well-behaved and failure-tolerant programs.

But, almost nothing that I mention above as a condition for this "to
happen" is true for C++, and I think it is very unlikely that this will
change.

speaking for myself,

David Chase
---
[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]





Author: clamage@Eng.Sun.COM (Steve Clamage)
Date: 1996/01/22
Raw View
In article 8k8@galaxy.ucr.edu, thp@cs.ucr.edu (Tom Payne) writes:
>Steve Clamage (clamage@Eng.Sun.COM) wrote:
>:
>: What we put in the language standard is binding on all implementations. We
>: try to specify things that can be implemented efficiently on any likely
>: system. In addition, we try to specify features so that they have no cost
>: (or nearly no cost) if you don't use them. IMHO, guarantees about what you
>
>Agreed!!
>
>: can do in an asynchronous signal handler don't meet those criteria for
>: inclusion in the C++ standard.
>
>That's a rather broad conclusion, given the discussion so far.

I don't agree. If you have control over the entire environment, you can
make more guarantees about behavior. For example, Ada implementations
have extensive requirements on what they must support. If a platform
cannot reasonably meet those requirements, you aren't going to find an
Ada implementation which is both conforming and useful.

C++, on the other hand, is intended to be dropped into (nearly) any existing
platform and coexist with other languages on that platform. The language
definition attempts to stay away from areas where common platforms have
widely differing behavior for that reason. Asynchronous signal handling
certainly varies widely among platforms.

It's easy to wave your hands and say that the implementation ought to
be relatively easy to do and not overly expensive. But what if the ABI
on a common platform makes that infeasible? If a language feature
limits the number of platforms which allow implementation, it should be
important to a wide range of programmers and programs.

---
Steve Clamage, stephen.clamage@eng.sun.com
---
[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]





Author: chase@centerline.com (David Chase)
Date: 1996/01/22
Raw View
In article <4dos4l$ra9@engnews1.Eng.Sun.COM>,
Steve Clamage <clamage@Eng.Sun.COM> wrote:
>In article k04@wcap.centerline.com, chase@centerline.com (David Chase) writes:

>I'm more than willing to assume your implementation technique has merit.
>Yet didn't you say you were not able to get it approved? So what
>is a C++ implementor to do if the only reasonable implementation
>technique violates the platform ABI?

Use of techniques not mandated by the ABI does not necessarily
"violate" the ABI.  For instance, Sun's current C++ product uses
PC-ranges, yet these are not discussed in the ABI.  Note that the C++
subroutines interoperate with ABI-conforming subroutines.  Placing
something like that in the ABI merely helps reduce the chance that
each and every language and vendor will do something different and
non-interoperable.  The actual reasons why it didn't make it in had a
lot less to do with technology, and more to do with intercompany
politics (and I must admit that I did not explain myself well at the
time).

>I want to say again that a criterion for a feature in the standard is not
>whether you can somehow implement it on some systems. The criterion is more
>like whether you can implement it with appropriate efficiency on all
>systems and not adversely affect programs that don't use the feature.
>If a feature does not meet this criterion, it has to be widely beneficial
>to justify its inclusion.

Well, most programs I've seen (Sparc, 386, 68K, VAX) used pretty
simple calling sequences, even in the presence of some scheduling, and
those programs aren't adversely affected by this.  It's efficient on
all reasonable systems (I haven't figured out how it would work on a
B1700, for example), and I've had my ear bent talking to people (at
Sun) doing video about how brain-dead they think it is to not have
asynchronous exceptions.  Furthermore, I fully expect that people will
do stupid stuff in signal handlers, no matter what the standard says.
I realize that there are difficulties (how much of the constructor has
completed?) but they aren't related to maintaining consistent
activation records.

Really, this is slightly pointless -- I had this argument with other
people years ago, and I know that it will have no effect on the
language.  However, it is simply not the case that it is difficult to
maintain consistent activation records in the presence of asynchronous
exceptions.

speaking for myself,

David Chase
---
[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]





Author: Dick Menninger <Dick.Menninger@daytonoh.attgis.com>
Date: 1996/01/22
Raw View
> ==========Tom Payne, 1/19/96==========
>
> Dick Menninger (Dick.Menninger@daytonoh.attgis.com) wrote:

> Good analysis, but I'm unclear about the conclusion.  Functions called
> by signal handlers should be allowed to throw exceptions.  If,
> however, the signal handler itself throws an exception or fails to
> catch one thrown to it, then the situation seems analogous to the base
> function of a thread throwing an exception or failing to catch one
> thrown to it.  Shouldn't we consider that a bug?

If a thread in a multi-threaded environment throws an
uncaught exception, something must happen.  That
something also applies to the signal handler's uncaught
exceptions unless another, more specific mechanism
is supplied.  For instance, since a C++ wrapper to the
signal handler is needed to determine this has happened,
the wrapper could have a standard default action function
that can be overridden by the app.  The language has
set the precedent of defining how uncaught exceptions
behave is some circumstances.  Once that door is open,
the language has to do it in the rest of them.

The above should also work in single-threaded environments,
as well.  It is just more obvious when thinking in terms
of multi-threaded environments.


Good Day
Dick
Dick.Menninger@DaytonOH.ATTGIS.COM
---
[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]





Author: Dick Menninger <Dick.Menninger@daytonoh.attgis.com>
Date: 1996/01/24
Raw View
> ==========Steve Clamage, 1/22/96==========

> In article 8k8@galaxy.ucr.edu, thp@cs.ucr.edu (Tom Payne) writes:
> >Steve Clamage (clamage@Eng.Sun.COM) wrote:

> >: What we put in the language standard is binding on all
> implementations. We
> >: try to specify things that can be implemented efficiently on
> any likely
> >: system. In addition, we try to specify features so that they
> have no cost
> >: (or nearly no cost) if you don't use them. IMHO, guarantees
> about what you

> >Agreed!!

> >: can do in an asynchronous signal handler don't meet those
criteria for
> >: inclusion in the C++ standard.

> >That's a rather broad conclusion, given the discussion so far.

> I don't agree. If you have control over the entire environment, you can
> make more guarantees about behavior. For example, Ada implementations
> have extensive requirements on what they must support. If a platform
> cannot reasonably meet those requirements, you aren't going to find an
> Ada implementation which is both conforming and useful.

> C++, on the other hand, is intended to be dropped into (nearly)
> any existing
> platform and coexist with other languages on that platform.
The language
> definition attempts to stay away from areas where common platforms have
> widely differing behavior for that reason. Asynchronous signal handling
> certainly varies widely among platforms.
>
> It's easy to wave your hands and say that the implementation ought to
> be relatively easy to do and not overly expensive. But what if the ABI
> on a common platform makes that infeasible? If a language feature
> limits the number of platforms which allow implementation, it should be
> important to a wide range of programmers and programs.

It is important for asynchronous threads that may interrupt other
threads (signal handlers, interrupt handlers, ...) to be able to use
the same exception semantics that any thread would use.  Else
you must define two sets of C++ behavior and STL, new, etc., must
all work in both.  You made exceptions part of the language, but
they still seem to be second class citizens.  Until they are made
first class citizens, you will continue to have a lot of arguing about
inherent problems of them being second class.

This is just one case where trying to limit the standard to ALL
potential environments seems to be hurting the thinking and
the language.  I suspect that essentially all environments can
actually do something sensible.  If a few cannot, they should
be exceptional, in that area, to the standard.

Good Day
Dick
Dick.Menninger@DaytonOH.ATTGIS.COM
---
[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]





Author: thp@cs.ucr.edu (Tom Payne)
Date: 1996/01/24
Raw View
Steve Clamage (clamage@Eng.Sun.COM) wrote:
: In article 8k8@galaxy.ucr.edu, thp@cs.ucr.edu (Tom Payne) writes:
: >Steve Clamage (clamage@Eng.Sun.COM) wrote:
: >:
: >: What we put in the language standard is binding on all implementations.
: >: We try to specify things that can be implemented efficiently on any
: >: likely system. In addition, we try to specify features so that they have
: >: no cost (or nearly no cost) if you don't use them.
: >
: >Agreed!!
: >
> >: IMHO, guarantees about what you
: >: can do in an asynchronous signal handler don't meet those criteria for
: >: inclusion in the C++ standard.
: >
: >That's a rather broad conclusion, given the discussion so far.
:
[...]
: C++, on the other hand, is intended to be dropped into (nearly) any existing
: platform and coexist with other languages on that platform. The language
: definition attempts to stay away from areas where common platforms have
: widely differing behavior for that reason. Asynchronous signal handling
: certainly varies widely among platforms.

There are certain core semantic features common to signal hanling in
all platforms, and IMHO we are not going outside them.  If a platform
support signals, all we need is a way to block (i.e., defer) them.

If the ABI implementation of signal blocking is missing or has high
overhead, then we can use global flags inside the program to reduce
blocking to setting a bit and reduce unblocking to clearing that bit
and checking whether a deferred signal has arrived (in which case
there is additional overhead to check which signal to process it).  We
can omit the handling of the blockage bit and instead use PC-range
techniques to check, on signal arrival, whether the flag would have
been set.  (David Chase has outline a more radical approach that
avoids the need to check the deferred-signal bit.)  In any case, we
are not counting on the ABI to have an efficient implementation of
signal blocking.

: It's easy to wave your hands and say that the implementation ought to
: be relatively easy to do and not overly expensive. But what if the ABI
: on a common platform makes that infeasible? If a language feature
: limits the number of platforms which allow implementation, it should be
: important to a wide range of programmers and programs.

Agreed!!  Note however that an increasing percentage of programs have
asynchornous aspects to them, under headings such as "event-driven",
"real-time", "multi-threaded", "parallel", "concurrent", etc.

Tom Payne (thp@cs.ucr.edu)
---
[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]





Author: wclodius@lanl.gov (WIlliam B. Clodius)
Date: 1996/01/25
Raw View
Note in the discussion of handlers for asynchronous exception no reference
has been made to existing implementations.  I believe Eiffel, and to a
much lesser extent, Ada, have asynchronous exception handling, and have
not suffered a significant performance degradation by the inclusion of
this capability in the language.  Am I correct in my belief, and do other
languages have such capabilities?

--
 William B. Clodius             Phone (505) 665-9370
 Los Alamos Natl. Lab. NIS-1    FAX (505) 665-7395
 PO Box 1663, MS-D466           Group Office (505) 667-2701
---
[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]





Author: David Chase <chase@centerline.com>
Date: 1996/01/25
Raw View
> Note in the discussion of handlers for asynchronous exception no reference
> has been made to existing implementations.  I believe Eiffel, and to a
> much lesser extent, Ada, have asynchronous exception handling, and have
> not suffered a significant performance degradation by the inclusion of
> this capability in the language.  Am I correct in my belief, and do other
> languages have such capabilities?

I think this depends on how you define "significant".  Dealing with
asynchronous exception handling in the formal data-flow-analysis
sense, it really trashes your flow graph.  That should make your
compilation take longer, and the result should be somewhat slower.
However, I'm not sure that "somewhat" exceeds 10%, most of the time.

As for other languages with async exception handling, I'm pretty
sure that the Acorn Modula-2+ compiler supported it, and it generated
code that was clean and efficient by the standards of its time (1988).
I'm pretty sure that the DEC-SRC M-2+ compiler also supported it,
and some of that technology may have made it back into the DEC binary
interfaces.

Oddly enough, I think you can "code to the compiler" with (asynchronous)
exception handling.  If, in your exception handler, you overwrite
every single variable that was set in your code (and perhaps visible
outside the exception handler) and if your flow analysis is looking
for this trick, then the compiler should generate code that is just
fine -- since all the exception kills all the values anyway, you
don't have to stand on your head in the unexceptional case to preserve
them for the case where control flows into the handler -- that is,
you can optimize them (there's an interesting dual to control-flow
here that I really ought to think about a little harder).

David
---
[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]





Author: clamage@Eng.Sun.COM (Steve Clamage)
Date: 1996/01/16
Raw View
In article 22h@galaxy.ucr.edu, thp@cs.ucr.edu (Tom Payne) writes:
>
>Implicit in a qestion of what the Standard says are the related
>questions of what it should say and why --- why shouldn't signal
>handlers be allowed to throw exceptions?  (The question seems both
>interesting and appropriate.)

Exceptions are synchronous, and unwind the stack from the point of the
throw to the point of the handler. When an asynchronous signal arrives,
what is the state of the stack? Answer: unknown. In particular, the
stack might not even be in a consistent state -- arguments half pushed
during function entry or half popped during exit.

In C, a signal handler isn't allowed to do much of anything, precisely
because the program state can't be known and may be inconsistent. The
same is true in C++.

Allowing exceptions to be thrown from a signal handler would place a
noticeable penalty on all programs to provide locks on every function
entry and exit, even programs that didn't throw exceptions or use
signals.
---
Steve Clamage, stephen.clamage@eng.sun.com
---
[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]





Author: clamage@Eng.Sun.COM (Steve Clamage)
Date: 1996/01/18
Raw View
In article p6m@galaxy.ucr.edu, thp@cs.ucr.edu (Tom Payne) writes:
>Steve Clamage (clamage@Eng.Sun.COM) wrote:
>: In article 22h@galaxy.ucr.edu, thp@cs.ucr.edu (Tom Payne) writes:
>: >why shouldn't signal
>: >handlers be allowed to throw exceptions?
>:
>: Exceptions are synchronous, and unwind the stack from the point of the
>: throw to the point of the handler. When an asynchronous signal arrives,
>: what is the state of the stack? Answer: unknown. In particular, the
>: stack might not even be in a consistent state -- arguments half pushed
>: during function entry or half popped during exit.
>
>When accessing any critical, shared data structure, it is standard
>practice to exclude interrupt-sustained pseudothreads (signal
>handlers) that access the same structure by blocking their
>corresponding signal.  The overhead should be minimal.

In time-critical programs on real-time systems, yes, locking overhead
needs to be minimal. Remember we are talking about the C++ language spec,
not an operating system spec. More below.

>: Allowing exceptions to be thrown from a signal handler would place a
>: noticeable penalty on all programs to provide locks on every function
>: entry and exit, even programs that didn't throw exceptions or use
>: signals.
>
>I'm not sure.  Signal blocking is required only in cases where signal
>handlers might collide with interrupted code over a critical, shared data
>structure.  But, independently compiled libraries must be prepared for
>the worst case.

Suppose that function entry and exit are not atomic operations, which is
the case on all systems supporting C++ that I am aware of. The "critical
structure" is the stack frame. If asynchronous interrupts can occur, and
if you are going to require well-defined exception behavior from signal
handlers, then you must lock the entirety of every function preamble and
postamble. (You cannot know that an external signal won't occur.) That
requirement not only slows down function calls, it adds to interrupt
latency.

How expensive is it to lock and unlock every function entry and exit?
On some systems it is cheap. On others it is expensive. Considering that
a characteristic of OO programs is having many small functions, requiring
these locks could have a dramatic impact on program performance, even
for programs that don't want to throw exceptions from signal handlers.

What we put in the language standard is binding on all implementations. We
try to specify things that can be implemented efficiently on any likely
system. In addition, we try to specify features so that they have no cost
(or nearly no cost) if you don't use them. IMHO, guarantees about what you
can do in an asynchronous signal handler don't meet those criteria for
inclusion in the C++ standard.
---
Steve Clamage, stephen.clamage@eng.sun.com
---
[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]





Author: Dick Menninger <Dick.Menninger@daytonoh.attgis.com>
Date: 1996/01/18
Raw View
> ==========Steve Clamage, 1/16/96==========

> In article 22h@galaxy.ucr.edu, thp@cs.ucr.edu (Tom Payne) writes:

> >Implicit in a qestion of what the Standard says are the related
> >questions of what it should say and why --- why shouldn't signal
> >handlers be allowed to throw exceptions?  (The question seems both
> >interesting and appropriate.)

> Exceptions are synchronous, and unwind the stack from the point of the
> throw to the point of the handler. When an asynchronous signal arrives,
> what is the state of the stack? Answer: unknown. In particular, the
> stack might not even be in a consistent state -- arguments half pushed
> during function entry or half popped during exit.

Signal handlers are analogous to interrupt handlers at
application level.  They form separate asynchronous
processing that may communicate to the rest of the
application but are really a separate thread.  How they
communicate to the rest of the application is colored
thoroughly by their nature.  The problem in thinking
about exceptions in signal handlers seems to be that
everybody is treating them as part of the thread they interrupt.
That leads you down the path to oblivion.  They should
be seen as a separate thread of execution.  An exception
does not go back through the special save boundary.
To do that would be like an exception in one thread
continuing through another threads stack.  When you
look at a signal handler as a threadlike thing that happens
to preempt another thread, you start making sensible
decisions that allow a signal handler to do that little
more that is probably necessary.  Since exceptions
are required at rather basic levels now, precluding
them is very unrealistic.

> In C, a signal handler isn't allowed to do much of anything, precisely
> because the program state can't be known and may be inconsistent. The
> same is true in C++.

It is just like an interrupt handler in that it could
deadlock with the code it preempts.  OSes deal with
that and do quite meaty stuff in the interrupt handlers.
I certainly hope you are NOT trying to preclude the
use of exceptions in interrupt handlers.  That would
be totally absurd.

> Allowing exceptions to be thrown from a signal handler would place a
> noticeable penalty on all programs to provide locks on every function
> entry and exit, even programs that didn't throw exceptions or use
> signals.

I don't think so.  That does not follow at all.
See the earlier comments.

Good Day
Dick
Dick.Menninger@DaytonOH.ATTGIS.COM
---
[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]





Author: chase@centerline.com (David Chase)
Date: 1996/01/19
Raw View
In article mca@engnews1.Eng.Sun.COM, clamage@Eng.Sun.COM (Steve Clamage) writes:
> Suppose that function entry and exit are not atomic operations, which is
> the case on all systems supporting C++ that I am aware of. The "critical
> structure" is the stack frame. If asynchronous interrupts can occur, and
> if you are going to require well-defined exception behavior from signal
> handlers, then you must lock the entirety of every function preamble and
> postamble. (You cannot know that an external signal won't occur.) That
> requirement not only slows down function calls, it adds to interrupt
> latency.

As near as I can tell, the best way to do this is to slightly enhance a
PC-range-based exception-handling specification.  I was pushing for
this for the Sparc V9 ABI when I worked at Sun, but it was tough
slogging.  I wrote an article for the JCLT a few years ago that
explained how to do exactly what you are talking about on Sparc  (two
issues in mid-1994).  The essential construct is not one that can be
expressed in C++ -- essentially, it is one where the exception handler
is within the guarded range, but the guarded range is written very
carefully (essentially, all the instructions but the last one in the
normal code sequence can be re-run as many times as necessary).  The
handler for any such guarded critical range finishes the range (e.g.,
gets you in or out of the activation record) and then does the normal
dispatch "as if" the exception arrived at a safe place.  Since stack
frame construction typically takes only a few instructions, whereas
exception dispatch takes many more, this will not have a noticeable
effect on the latency of exception delivery.  Locking is not required,
so you don't pay for that, either.  This technique is portable (as far
as I can tell, from a cursory study) to all RISC architectures, and I
suspect it would port to Intel without too much trouble.

> What we put in the language standard is binding on all implementations. We
> try to specify things that can be implemented efficiently on any likely
> system. In addition, we try to specify features so that they have no cost
> (or nearly no cost) if you don't use them. IMHO, guarantees about what you
> can do in an asynchronous signal handler don't meet those criteria for
> inclusion in the C++ standard.

I think I've just described a way to do this that is efficient on any
likely system, and that has no runtime cost if you don't use it.  You
can read about it in a journal.  It isn't, to my knowledge, patented.
There's an expansion of code and table space, but if you engineer it
right (take a look at how Sun does their PC-ranges for C++ exceptions;
they're completely position-independent, and need not even be paged
in from disk unless an exception is raised) you'll never load it into
memory.

An additional stunt is simply to have your exception-handler recognize
standard function pre and post-ambles, or standard phases of activation
record construction, and avoid the need for additional code.  For
instance, it could merely interpret the preamble to the end, then raise
the exception, and that would not cost more than 100 instructions
(figure 20x cost to interpret 5 instructions).  In the case of the
Sparc SvR4 ABI, there's one way to unwind a leaf routine, and another
way to unwind a normal routine.  There's a variety of ways to solve
this problem, depending upon your code size and latency and throughput
constraints.

Of course, some of this may seem like magic to some people, but then maybe
those people shouldn't be implementing C++.

speaking for myself,

David Chase
---
[ comp.std.c++ is moderated.  Submission address: std-c++@ncar.ucar.edu.
  Contact address: std-c++-request@ncar.ucar.edu.  The moderation policy
  is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]