EPICS Controls Argonne National Laboratory

Experimental Physics and
Industrial Control System

2002  2003  2004  2005  <20062007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024  Index 2002  2003  2004  2005  <20062007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
<== Date ==> <== Thread ==>

Subject: RE: 3.15 C++ Exception classes
From: "Jeff Hill" <[email protected]>
To: "'Andrew Johnson'" <[email protected]>, "'EPICS core-talk'" <[email protected]>
Date: Thu, 23 Feb 2006 16:34:15 -0700
Ok, so I finally get some time to respond concerning this matter. This is
one of those situations where the longer you wait the more back-log there is
to read, and the longer it takes to respond...

Anyways, hope that you find my ramblings are relevant.

Subject 1) The "virtual severity_t severity () const" interface.

In the legacy CA client library's exception interface this was used to
distinguish between failures that were caused by undiagnosed faults (usually
programming errors) and failures that were caused by expected changes in
external conditions such as network disconnects. So to answer Ben's concern,
my intent was definitely for all exceptions to result from failures. 

For example, if a CA put (not a put callback) is sent to the IOC and it
fails because the device is turned off it might be best to print a message,
but not abort the program, in the default exception handler. From this
example one can possibly surmise that this severity information might be
useful only to a default exception handler. When a user replaces the default
exception handler they might be unlikely to care about the severity.

One could argue that the severity info answers a need of CA (which has
default exception handlers installed) and should be in a CA specific
exception class hierarchy.

That severity returning function was originally conceived partly with the
idea of speeding up mapping the C++ CA client API to the legacy C base
interface. It might be that CA needs (or needs not) to derive from the core
exception class to provide such mappings.

I guess the question we need to answer is if facilities (including
facilities other than CA) might have default exception handlers that need to
choose between conditions that terminate and conditions that need only a
diagnostic message.

For example one exception might cause an IOC to restart some part of itself
and another exception might cause the IOC only to print a diagnostic
message. However if the IOC was a snap-in into an overarching component then
that component might define a different exception handling policy.

Subject 2) A severity returning function verses an augmented exception
hierarchy.

Of course the trade off here is more or less catch phrases in the exception
handler. 

Case A:

Catch ( warning & )
{
}
Catch ( error & )
{
}
Catch ( severe & )
{
}

Case B:

Catch ( Exception & e ) {
	Print e.what () 
	Print ( e.severity() )
}

Now, admittedly, if Ben is right and we only need really to track two
situations {unexpectedFault, externalConditionInfluencedFault} then there
would need to be only two catch phrases. That can't be difficult.

Subject 3) The exception interface should look exactly like std::exception

I think that we all agree that all exceptions should derive from
std::exception. What we are investigating is if some additional augmentation
of that interface might be useful. Presuming that we are successful, then we
can guess that this augmentation certainly can't look exactly like the base
std::exception interface.

Subject 4) What is this "void context (StringEditor & ) const" interface
there for anyways?

When I designed that interface my thought was that "const char * what ()
const" should never return a pointer to dynamically allocated storage. If it
ever did and the user held onto that pointer after the exception object was
destroyed there could be an unexpected failure. Admittedly, we could place
the burden of doing the right thing on the user, but generally the hallmark
of good interface design is avoidance of this sort of grey areas.

So, considering that line of thought, I was inclined to have "const char *
what () const" return a linker allocated string containing a human readable
but compile time fixed description of the problem. This string would be
required to have a lifespan of forever (or at least as long as the program
was loaded into memory).

The "void context (StringEditor & ) const" was added to return additional
run time varying details about the problem. For example, if the put fails
because the device is off "what()" might return "Device not present", and
"context()" might return "rack 10, crate 4, slot 6, signal 7". The exception
payload might not contain a string but instead only the following.

int rack;
int crate;
int slot;
int signal;

I also prefer to not call new() within the exception unwind. Admittedly, as
Andrew mentions, if one catches any bad_alloc exceptions that might occur
and deals with them, this can be reasonably robust but overall I still think
that since there are easy ways to avoid complexity and fragmentation
associated with use of new (i.e. interfaces ala StringEditor or
StringSegment) then why burden the exception unwind with this additional
overhead, uncertainty, and fragmentation of new.

If an exception handler knows how to catch the upgraded interface it can
show context() and what() related information, and if the exception payload
doesn't have the upgraded interface the exception handler can fall back to
the what() related information.

Subject 5) Forwarding exceptions

If one defines exception specifications (I typically do not) it may be
necessary to code like this:

catch ( something & ) {
	throw somethingElse ();
}

I observe this to be a very significant cause of users not seeing the
details they need to see to get a configuration error fixed. Perhaps, our
core infrastructure needs to make it easy for code authors to do the right
thing in this type of situation. This is a better alternative.

catch ( something & ) {
	throw somethingElse ( something );
}

To do a good job in this type of situation we need to copy what was returned
by something::what() and also something::context() into the somethingElse
payload. 

We could jump to the conclusion that this is an argument for use of new, but
I think that StringEditor allows a better alternative based on
non-contiguous string storage implementation thereby avoiding memory
fragmentation. And, such details might be hidden from naive users.

Subject 6) Shouldn't it be "void what (StringEditor & ) const" instead of
"void context (StringEditor & ) const"

Of course we need to agree on what the purpose of the function is before we
name it ;-). Overloading is only a good idea if the two interfaces are
functionally equivalent.

Subject 7) The "virtual long status() const" interface

I agree that this is a useful idea, but maybe the functionality is
invariably application specific - and therefore we may need to be careful.
There are, invariably, many different status code spaces. CA has one. There
is also the vxWorks style error codes used in the IOC and the portable
server. I am sure that there are others.

So this is a good idea, but perhaps it needs to be placed in a further
derived exception interface.

I think that the fact that this is needed only for efficient conversion to
legacy C interfaces is another argument for placing this in a further
derived superset interface.

Subject 8) Exception hierarchy isn't needed

Improved organization and structure is probably always a good idea IMHO.
Some of that will of course be application specific and should not be in a
core exception classes. There is definitely room for improvement in my code
in this area.

Jeff

> -----Original Message-----
> From: Andrew Johnson [mailto:[email protected]]
> Sent: Monday, February 20, 2006 4:21 PM
> To: EPICS core-talk
> Subject: 3.15 C++ Exception classes
> 
> Last September, Jeff Hill sent me this class definition, with the
> suggestion that something like this be adopted as the basis for future
> EPICS exception objects:
> 
> > struct Diagnostic : exception {
> > public:
> >     enum severity_t {
> >         sevWarning, sevError, sevFatal };
> >     virtual severity_t severity () const = 0;
> >     virtual void context ( StringSegment & ) const = 0;
> > };
> 
> Having recently committed my StringReader and StringEditor interfaces
> and some implementations to the 3.15 CVS tree for Jeff to use in
> DataAccess, I am looking at designing a modified version of this class
> for general use.  The main point of this email is to document what I'm
> currently implementing, but I guess that this may result in some
> discussion from Jeff and others as well.
> 
> severity(): I don't like this; the severity information should be
> implicit in the hierarchy of the class that is being thrown.  I expect
> to be able to write a try/catch phrase that could catch warnings but not
> errors or fatalities; I don't want to catch everything and then have to
> re-throw anything that's more severe than a warning.  I'm also not
> convinced that the thrower can determine the severity of an exception in
> practice.  Therefore I'm not going to include the severity part.
> 
> context(): I'm replacing Jeff's StringSegment with a StringEditor and
> renaming this function to what(), since it performs the exact same role
> as the std::exception::what() function, namely provides a way to convert
> the exception data into a displayable string.
> 
> status(): We often provide wrappers to allow C code to call C++ code.
> The C routines can't trap exceptions, so those C++ wrappers may have to
> convert such exceptions into a long integer status value.  The exception
> object is the obvious thing to know what status value to return, so I'm
> considering adding this method to provide that.  If the conversion to
> the single C status value would lose diagnostic data that is stored in
> the exception object, this routine can log that information to the error
> logger at that time - status() should only be called once, when the
> exception is about to be passed to C code.
> 
> Here's my current replacement base class:
> 
> class BaseException :
>      public std::exception {
> public:
>      virtual void what(StringEditor &str) const = 0;
>      virtual long status() const {
>          return S_exc_exception;
>      }
> };
> 
> - Andrew
> --
> There is no S in exprexxo.



References:
3.15 C++ Exception classes Andrew Johnson

Navigate by Date:
Prev: Re: 3.15 C++ Exception classes Andrew Johnson
Next: Re: 3.15 C++ Exception classes Benjamin Franksen
Index: 2002  2003  2004  2005  <20062007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
Navigate by Thread:
Prev: Re: 3.15 C++ Exception classes Andrew Johnson
Next: Re: 3.15 C++ Exception classes Andrew Johnson
Index: 2002  2003  2004  2005  <20062007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
ANJ, 02 Feb 2012 Valid HTML 4.01! · Home · News · About · Base · Modules · Extensions · Distributions · Download ·
· Search · EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing ·