Branch data Line data Source code
1 : : // *****************************************************************************
2 : : /*!
3 : : \file src/Base/ProcessException.cpp
4 : : \copyright 2012-2015 J. Bakosi,
5 : : 2016-2018 Los Alamos National Security, LLC.,
6 : : 2019-2021 Triad National Security, LLC.,
7 : : 2022-2024 J. Bakosi
8 : : All rights reserved. See the LICENSE file for details.
9 : : \brief Process an exception
10 : : \details This file contains the implementation of processing an exception.
11 : : Logically, it would make sense to put this into Exception.C, however,
12 : : Exception.h is included by all who want to be able throw an exception (a
13 : : potentially large number of files) and that would pull in the charm++.h as
14 : : well as the mpi.h headers, which triggers a slew of compiler warnings. On
15 : : the other hand, processing an exception is only done by the executables'
16 : : main chares objects and a few select explicit main() routines that use MPI,
17 : : which is a lot less than those which throw, so processing an exception is
18 : : separated here.
19 : : */
20 : : // *****************************************************************************
21 : :
22 : : #include <cstdio>
23 : : #include <csignal>
24 : : #include <exception>
25 : : #include <cfenv>
26 : :
27 : : #include "NoWarning/charm.hpp"
28 : : #include "NoWarning/mpi.hpp"
29 : :
30 : : #include "Exception.hpp"
31 : : #include "ProcessException.hpp"
32 : : #include "XystBuildConfig.hpp"
33 : :
34 : : namespace tk {
35 : :
36 : : void
37 : 1 : signalHandler( int signum )
38 : : // *****************************************************************************
39 : : // Signal handler for multiple signals, SIGABRT, SIGSEGV, etc.
40 : : //! \param[in] signum Signal number
41 : : //! \see https://oroboro.com/stack-trace-on-crash
42 : : //! \details Signals caught:
43 : : //! SIGABRT is generated when the program calls the abort() function, such as
44 : : //! when an assert() triggers
45 : : //! SIGSEGV is generated when the program makes an illegal memory access, such
46 : : //! as reading unaligned memory, dereferencing a null pointer, reading
47 : : //! memory out of bounds etc.
48 : : //! SIGILL is generated when the program tries to execute a malformed
49 : : //! instruction. This happens when the execution pointer starts reading
50 : : //! non-program data, or when a pointer to a function is corrupted.
51 : : //! SIGFPE is generated when executing an illegal floating point instruction,
52 : : //! most commonly division by zero or floating point overflow.
53 : : // *****************************************************************************
54 : : {
55 : : // associate each signal with a signal name string.
56 : 1 : const char* name = nullptr;
57 [ + - ][ - - ]: 1 : switch( signum ) {
[ - - ][ - ]
58 : 1 : case SIGABRT: name = "SIGABRT"; break;
59 : 0 : case SIGFPE: name = "SIGFPE"; break;
60 : 0 : case SIGILL: name = "SIGILL"; break;
61 : 0 : case SIGINT: name = "SIGINT"; break;
62 : 0 : case SIGSEGV: name = "SIGSEGV"; break;
63 : 0 : case SIGTERM: name = "SIGTERM"; break;
64 : : }
65 : :
66 : : // Echo what signal is caught
67 [ + - ]: 1 : if ( name )
68 : 1 : fprintf( stderr, "Caught signal %d (%s)\n", signum, name );
69 : : else
70 : 0 : fprintf( stderr, "Caught signal %d\n", signum );
71 : :
72 : : // Get and display backtrace
73 [ + - ][ + - ]: 1 : tk::Exception("Signal caught").handleException();
[ + - ]
74 : :
75 : : // Pass the signual number to the runtime system to use as exit code
76 : 1 : CkExit( signum );
77 : 0 : }
78 : :
79 : : int
80 : 283 : setSignalHandlers()
81 : : // *****************************************************************************
82 : : // Set signal handlers for multiple signals, SIGABRT, SIGSEGV, etc
83 : : //! \return Ignore, used for calling in a constructor's initializer list
84 : : // *****************************************************************************
85 : : {
86 : : // override Charm++'s terminate handler
87 : 283 : std::set_terminate( [](){
88 [ + - ][ + - ]: 1 : tk::Exception("Terminate was called").handleException();
[ + - ]
89 : : // Tell the runtime system to exit with a nonzero exit code
90 : 1 : CkExit(1);
91 : 0 : } );
92 : :
93 : 283 : signal( SIGABRT, tk::signalHandler );
94 : 283 : signal( SIGFPE, tk::signalHandler );
95 : 283 : signal( SIGILL, tk::signalHandler );
96 : 283 : signal( SIGINT, tk::signalHandler );
97 : 283 : signal( SIGSEGV, tk::signalHandler );
98 : 283 : signal( SIGTERM, tk::signalHandler );
99 : :
100 : 283 : feenableexcept( FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW );
101 : :
102 : 283 : return 0;
103 : : }
104 : :
105 : : void
106 : 1 : processExceptionCharm()
107 : : // *****************************************************************************
108 : : // Process an exception from the Charm++ runtime system
109 : : //! \details See Josuttis, The C++ Standard Library - A Tutorial and Reference,
110 : : //! 2nd Edition, 2012.
111 : : // *****************************************************************************
112 : : {
113 : : try {
114 : 1 : throw; // rethrow exception to deal with it here
115 : : }
116 : : // Catch tk::Exception
117 [ + - ][ - ]: 1 : catch ( tk::Exception& qe ) {
118 [ + - ]: 1 : if (!CkMyPe()) qe.handleException();
119 : 1 : }
120 : : // Catch std::exception and transform it into tk::Exception without
121 : : // file:line:func information
122 : 0 : catch ( std::exception& se ) {
123 [ - - ][ - - ]: 0 : tk::Exception qe( se.what() );
[ - - ]
124 [ - - ]: 0 : if (!CkMyPe()) qe.handleException();
125 : 0 : }
126 : : // Catch uncaught exception
127 : 0 : catch (...) {
128 [ - - ][ - - ]: 0 : tk::Exception qe( "Non-standard exception" );
[ - - ]
129 [ - - ]: 0 : if (!CkMyPe()) qe.handleException();
130 : 0 : }
131 : :
132 : : // Tell the runtime system to exit with a nonzero exit code
133 : 1 : CkExit(1);
134 : 0 : }
135 : :
136 : : } // tk::
|