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