On Mon, 31 Aug 2015, Michael Povolotskyi wrote:

> Why do you put the error handler inside the library?

As with every other "Why do you put X inside libmesh?" question,
it's a combination of good sense (useful stuff should go in *some*
library to get reused) and laziness (error handling isn't
FEM-specific, so it could go in a separate library and be useful to
more than libMesh users, but we haven't yet figured out a good way to
separate out all our more-general library components without adding
more work for libMesh developers).

> Imagine that my application has many libraries, each of them has its
> own handler, how this should work together?

Take a look inside libmesh_terminate_handler() (and at the
set_terminate call in the same file).  When installing our handler, we
save the pre-existing handler, and then the last thing our handler
does is to call that pre-existing handler.

If other libraries behave this way, then everything works together:
you initialize libraries A, B, C, then D; this leaves the C++
terminate handler set to handler_D, which then calls handler_C, which
then calls handler_B, which then calls handler_A.

If you want to do this with parallel libraries, then you run into one
more problem: in a crash someone should call MPI_Abort() (to prevent
runs from just hanging and burning CPU time on large systems), but
calling MPI_Abort() kills the program before it can ever get to an
older terminate handler.  In this case the solution is to either make
sure there is no older terminate handler (make libMesh the first
library you initialize) or handle MPI yourself (call MPI_Init() before
constructing LibMeshInit, and we'll detect that we're not in charge of
MPI, so we won't ever call MPI_Init or MPI_Abort) and install your own
handler_A that does MPI_Abort only after everyone else's handler is
done.

> It is convenient that libmesh throws exceptions that explain what went
> wrong.
> Still I'd like to catch them in my application, not in the library.

This requirement is actually the reason *why* we use C++ exceptions
instead of a simpler abort().

If you wrap libMesh operations in a try/catch block, you can catch
anything libMesh throws, and the terminate handler never gets called.
In C++ the terminate handler *only* gets called if an exception was
uncaught: i.e. it was not called from a try block, or the exception
type doesn't match the specification you give "catch".  Setting a
terminate handler does *not* prevent your application from catching
exceptions.

Now, in practice I'm not sure how useful this is.  We usually only
throw exceptions when something has gone horribly unexpectedly wrong
or when there's been a convergence failure that the solver can't find
any allowable way to recover from, and in the former case it's hard to
say how much recovery you can do.  In my own applications I've merely
used try/catch blocks to output restart files before exiting.  That
was useful for getting checkpoint files when the solver was being
overtaxed, but it would have been a *lot* more complicated to do
anything useful in the case of e.g. an MPI desynchronization.
---
Roy

------------------------------------------------------------------------------
_______________________________________________
Libmesh-users mailing list
Libmesh-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/libmesh-users

Reply via email to