octave-maintainers
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: sparse matrices and error handling


From: John W. Eaton
Subject: Re: sparse matrices and error handling
Date: Sun, 17 Nov 2002 19:42:22 -0600

On 17-Nov-2002, Paul Kienzle <address@hidden> wrote:

| IIRC, SuperLU needs to be compiled with an error function defined which
| prints the error and exits.  I don't believe it allows for an error
| handler which returns.  It's been a long time since I looked at it though.

Then I think the right thing to do is use setjmp and
octave_jump_to_enclosing_context from the error handler, though more
cleanup may be needed if SuperLU allocates resources.  If it is not
possible to do that without modifying SuperLU, then we may want to
consider distributing a modified version with Octave, in which case we
can probably avoid the need for setjmp/longjmp.

| BTW, isn't it a misnomer to refer to the setjmp/longjmp setup as only
| applying to foreign code?  It seems to me that you would want it around
| any code which can take more than 1/2 second or so to complete, even
| if it is coded in C++ and is part of liboctave.  If you don't have it,then
| how can you break out of such code since Ctrl-C can't directly throw an
| exception?

In code that we can modify (all of Octave) we can use the new
OCTAVE_QUIT macro.  It checks to see if an interrupt has occurred, and
if so, throws an exception.  So everything that is not part of Octave
and that doesn't allow us to insert checks for the interrupt state and
maybe throw exceptions is "foreign code" that has to handle interrupts
some other way.  The simplest way seems to be a longjmp out of a
signal handler and back to the location where the foreign code was
called, then throw an exception.

| The usual question of cost and convenience.
| 
| In order to properly collect resources after exceptions you have to write
| your code just so.

I'd say it is much harder to get this right without exception
handling, because you would have store a pointer to everything you
need to free, even for local objects.  For example, we currently have
a lot of code that does something like

  some_fun (...) {
    ...
    Matrix mx (m, n);
    ...
  }

and as it is now, the memory allocated for mx will not be deleted if
we longjmp while this function is active.  To handle this, we would
need to write something like

  some_fun (...) {
    // Need to mark beginning of frame in unwind_protect list.
    unwind_protect::begin_frame ();
    ...
    Matrix mx (m, n);
    unwind_protect_local_matrix (mx);
    ...
    // Would not delete here, the Matrix destructor handles that, so
    // we need to discard info about locally allocated objects.
    unwind_protect::run_frame_discarding_local_objects ();
  }

for *every* matrix allocated this way.  Seems like a huge cost to me,
even if we added the unwind protect code to the Matrix constructor
(though that seems like a bad mixture to me).

Exception handling saves a lot of work for things like this because it
guarantees that if an exception causes us to unwind the call stack,
destructors for any live local objects will be called.

| I don't yet have a feel for how inconvenient "just so"
| is.  Is it much less hassle than unwind_protect?

Typically it just means making sure that resources are allocated in
constructors and released in destructors.  To be safe, you need to be
careful about how write the constructors and destructors, but I don't
think it is really hard.  Not all of Octave has it right yet, but for
the most part, resources are handled in constructors and destructors.

| I would also like to know how much it costs compared to unwind_protect.

I don't really know, though I suspect that it is not all that much.
There is a huge benefit compared to not using exceptions, since
Octave's unwind_protect is really only handling some resources.
Anything that is allocated as a local object will not go away if we
call longjmp from a signal handler to go back to the top level.  With
exception handling, we will clean up everything allocated that way
when we go back up the call stack.  We would still have to handle
things allocated outside of constructors, but we have to worry about
those things anyway.  Moving allocations like that inside constructors
is probably one of the better ways to solve the problem.  The C++
auto_ptr class can help.

jwe



reply via email to

[Prev in Thread] Current Thread [Next in Thread]