Sierra Toolkit  Version of the Day
Exception.cpp
1 
10 #include <stdexcept>
11 #include <exception>
12 #include <new>
13 #include <typeinfo>
14 #include <ios>
15 #include <string>
16 #include <sstream>
17 #include <iostream>
18 
19 #include <assert.h>
20 
21 #include <stk_util/diag/Env.hpp>
22 #include <stk_util/diag/Platform.hpp>
24 #include <stk_util/parallel/ExceptionReport.hpp>
26 #include <stk_util/diag/String.hpp>
27 #include <stk_util/diag/Trace.hpp>
28 
30 
31 namespace sierra {
32 
33 void
35 {}
36 
37 
38 ParallelThrowRegistry &
40 {
41  static ParallelThrowRegistry s_parallelThrowRegistry;
42 
43  return s_parallelThrowRegistry;
44 }
45 
46 
47 ParallelThrowRegistry::Registry::Registry()
48 {}
49 
50 
51 ParallelThrowRegistry::Registry::~Registry()
52 {
53  // Truely sick. Each is registered twice, once for the parallel version of the
54  // exception and once for the <stdexcept> base class version. The double increment
55  // keeps from deleting it twice. See ParallelThrowRegistry::registerException.
56  for (iterator it = begin(); it != end(); ++it, ++it)
57  delete (*it).second;
58 }
59 
60 
61 ExParallel &
62 ParallelThrowRegistry::register_exception_a(
63  const std::type_info & exception_type,
64  ExParallel * exception)
65 {
66  if (!findException(exception_type)) {
67  m_registry.push_back(Registry::value_type(&exception_type, exception));
68  mpih::Add_Handle(*exception);
69  }
70  return *exception;
71 }
72 
73 ExParallel *
75  const std::type_info & exception_type)
76 {
77  for (Registry::iterator it = m_registry.begin(); it != m_registry.end(); ++it)
78  if (*(*it).first == exception_type)
79  return (*it).second;
80 
81  return NULL;
82 }
83 
84 
85 void
87 {}
88 
89 
90 void
92  const std::exception & x,
93  const std::string & append_message)
94 {
96  if (!exception)
98 
99  exception->clear();
100  *exception << x.what() << append_message;
101 
102  exception->throw_copy();
103 }
104 
105 
106 void
108 {
109  BadException x;
110  x << "Unknown exception";
111  set_exception(static_cast<ExParallel &>(x));
112 }
113 
114 
115 void
117  std::exception & x)
118 {
119  ExParallel *registered_exception = ParallelThrowRegistry::instance().findException(typeid(x));
120 
121  if (!registered_exception)
122  registered_exception = ParallelThrowRegistry::instance().findException(typeid(Exception));
123 
124  registered_exception->setDescription(x.what());
125  registered_exception->setTraceback(Diag::Traceback::printTraceback(Diag::Traceback::snapshot()));
126 
127 // std::cerr << "Exception " << demangle(typeid(*registered_exception).name()) << " will be thrown from processor " << Env::parallel_rank() << " on the next MPIH function:" << std::endl
128 // << registered_exception->getDescription() << std::endl
129 // << registered_exception->getTraceback() << std::endl;
130 
131  mpih::Set_Local_Handle(const_cast<ExParallel &>(*registered_exception));
132 }
133 
134 
135 void
137  ExParallel & x)
138 {
139  ExParallel *registered_exception = ParallelThrowRegistry::instance().findException(typeid(x));
140 
141  if (!registered_exception)
142  registered_exception = ParallelThrowRegistry::instance().findException(typeid(Exception));
143 
144  registered_exception->setDescription(x.getDescription());
145  registered_exception->setTraceback(Diag::Traceback::printTraceback(Diag::Traceback::snapshot()));
146 
147 // std::cerr << "Exception " << demangle(typeid(*registered_exception).name()) << " will be thrown from processor " << Env::parallel_rank() << " on the next MPIH function:" << std::endl
148 // << registered_exception->getDescription() << std::endl
149 // << registered_exception->getTraceback() << std::endl;
150 
151  mpih::Set_Local_Handle(const_cast<ExParallel &>(*registered_exception));
152 }
153 
154 
155 void
157 {
158  mpih::Enable();
159 
164  LogicError::registerException();
165  DomainError::registerException();
166  InvalidArgument::registerException();
167  LengthError::registerException();
168  OutOfRange::registerException();
169  RuntimeError::registerException();
170  RangeError::registerException();
171  OverflowError::registerException();
172  UnderflowError::registerException();
174 
175  mpih::Activate_Handles();
176 }
177 
178 
179 void
181  MPI_Comm mpi_comm)
182 {
183  int nprocs;
184  MPI_Comm_size(mpi_comm, &nprocs);
185 
186  ExParallel **handles = new ExParallel* [nprocs];
187 
188  mpih::Get_Global_Handles(handles);
189 
190  MPIH_Handler_compete handler_compete_fn;
191  MPIH_Handler_execute handler_execute_fn;
192  mpih::Get_Functions(&handler_compete_fn ,
193  &handler_execute_fn);
194 
195  /* Now that we have the handles,
196  * reset the handles so we don't throw again. This way
197  * whatever function catches the exception we are about to
198  * throw can call mpih and mpih will not just throw again.
199  */
200  mpih::Reset_Local_Handle();
201 
202  /* First iterate through all of the exceptions thrown on all of
203  * the processors, and if any of them were thrown on this
204  * processor, print an error message and a traceback.
205  * only the owning processor will have the traceback information.
206  */
207  /* Iterate through all of the exceptions thrown on all of the processors
208  * and call the parallel_handler() function defined by any derived from
209  * ExParallel. This is done across all processors so that
210  * it is valid to do collective communication inside of parallel_handler()
211  */
212  for (int i = 0; i < nprocs; ++i) {
213  if (handles[i]) {
214  ExParallel *x = dynamic_cast<ExParallel *>(handles[i]);
215  if (x)
216  x->parallel_handler();
217  }
218  }
219 
220  /* Iterate through all of the exceptions thrown on all of the processors
221  * and select the one to throw in parallel on all processors. We would
222  * like to find one derived from ExParallel.
223  */
224 
225  ExParallel *the_exception = NULL;
226  int originating_processor = -1;
227 
228  for (int i = 0; i < nprocs; ++i) {
229  if (handles[i]) {
230  ExParallel *x = dynamic_cast<ExParallel *>(handles[i]);
231  if (x) {
232  if (handler_compete_fn)
233  (handler_compete_fn) (reinterpret_cast<void **>(&handles[i]), the_exception);
234  if ( handles[i] != the_exception ) {
235  the_exception = x;
236  originating_processor = i;
237  }
238  }
239  }
240  }
241 
242  delete [] handles;
243 
244  /* Since this function is called in parallel, it is possible
245  * to perform collective communication. Here the traceback
246  * and error messages are broadcast and set on all processors.
247  * These are the only two fields that are guarenteeded to be
248  * in each exception class. Other data stored in specialized
249  * derived classes will have to be communicated seperately.
250  * If needed this communication could be added to a virtual
251  * base class. That is a future enhancements depending on
252  * the demand.
253  */
254  if (the_exception) {
255  // Copy the description from the originating process to everywhere.
256  std::string description(the_exception->getDescriptionStream().str());
257  int description_len = description.length();
258  MPI_Bcast(&description_len,
259  1,
260  MPI_INT,
261  originating_processor,
262  mpi_comm);
263 
264  char *description_buf = new char[description_len];
265  description.copy(description_buf, description_len);
266 
267  MPI_Bcast(description_buf,
268  description_len,
269  MPI_CHAR,
270  originating_processor,
271  mpi_comm);
272 
273  // Copy the traceback stack from the originating process to everywhere.
274  const std::string &traceback(the_exception->getTraceback());
275  int traceback_len = traceback.length();
276  MPI_Bcast(&traceback_len,
277  1,
278  MPI_INT,
279  originating_processor,
280  mpi_comm);
281 
282  char *traceback_buf = new char[traceback_len];
283  traceback.copy(traceback_buf, traceback_len);
284 
285  MPI_Bcast(traceback_buf,
286  traceback_len,
287  MPI_CHAR,
288  originating_processor,
289  mpi_comm);
290 
291  // Rebuild the exception from the broadcasted data
292  the_exception->setDescription(std::string(description_buf, description_len));
293  the_exception->setTraceback(std::string(traceback_buf, traceback_len));
294  the_exception->setParallel(originating_processor);
295 
296 // std::cerr << "Throwing exception " << demangle(typeid(*the_exception).name()) << " in parallel" << std::endl
297 // << the_exception->getDescription() << std::endl
298 // << the_exception->getTraceback() << std::endl;
299 
300 #ifdef SIERRA_MPIH_VERBOSE
301  Env::outputP0()
302  <<"*************** Exception handling ***************"<<endl
303  <<" A parallel exception of type "<< typeid(*the_exception).name()<<endl
304  <<" will be thrown on all processors."<<endl;
305 #endif
306 
307  delete [] traceback_buf;
308  delete [] description_buf;
309  the_exception->throw_copy();
310  }
311  else {
312 #ifdef SIERRA_MPIH_VERBOSE
313  Env::outputP0()
314  <<"*************** Exception handling ***************"<<endl
315  <<" A parallel exception of type Unknown_Exception"<<endl
316  <<" will be thrown on all processors."<<endl;
317 #endif
318  throw Exception();
319  }
320 }
321 
322 } // namespace sierra
ExParallel & clear()
Member function clear clears the contents of the exception.
Definition: Exception.hpp:354
void sierra_exception_throw()
Member function sierra_exception_throw is called whenever a parallel exception is constructed...
Definition: Exception.cpp:34
void parallel_throw(MPI_Comm mpi_comm)
Function parallel_throw throws a consistant exception in parallel. parallel_throw is called after the...
Definition: Exception.cpp:180
Definition: Env.cpp:53
std::ostream & outputP0()
Function outputP0 returns the processor output log stream on processor 0 and the null log stream on a...
Definition: Env.cpp:271
void throw_copy(const std::exception &x, const std::string &append_message)
Function throw_copy throws a copy of the exception. The exception is located in the parallel exceptio...
Definition: Exception.cpp:91
virtual const char * what() const
Member function what returns the exception&#39;s description.
Definition: Exception.hpp:339
std::ostringstream & getDescriptionStream()
Member function getDescriptionStream returns the stream used to assemble the description.
Definition: Exception.hpp:394
ExParallel * findException(const std::type_info &exception_type)
Member function findException returns a pointer to the matching exception in parallel exception regis...
Definition: Exception.cpp:74
std::string getDescription() const
Member function getDescription returns the exception&#39;s description.
Definition: Exception.hpp:383
Template ExTemp takes a zero argument exception and makes it into a parallel throwable and put-to-abl...
Definition: Exception.hpp:536
ExParallel & setTraceback(const std::string &traceback)
Member function setTraceback sets the exception&#39;s traceback to the caller generating the exception...
Definition: Exception.hpp:418
static std::string printTraceback(const TracebackStack &traceback_stack)
Member function printTraceback writes the traceback stack function specifications to the output strea...
void set_exception()
Function set_exception is called on a single processor when an exception is caught. The next collective communication will propogate the exception to all processors. This flavor is called when an unknown exception (...) is caught.
Definition: Exception.cpp:107
static ParallelThrowRegistry & instance()
Member function instance returns the singleton instance for the parallel exception registry...
Definition: Exception.cpp:39
Class ParallelThrowRegistry is a registry of known parallel exceptions. For the negotiation of parall...
Definition: Exception.hpp:182
ExParallel & setParallel(int parallel)
Member function setParallel sets the originating processor for an exception that is being thrown in p...
Definition: Exception.hpp:443
virtual void parallel_handler()
Member function parallel_handler is called just before a parallel exception is thrown. It is guaranteed to be called in parallel on all processors, so collective communication is allowed inside Parallel_Handler. This function might be used to copy information to all processors. The default is to do nothing.
Definition: Exception.cpp:86
static void registerException()
Member function registerException registers the exception with the parallel exception registry...
Definition: Exception.hpp:638
void register_stl_parallel_exceptions()
Member function register_stl_parallel_exceptions registers the stl exceptions with the parallel excep...
Definition: Exception.cpp:156
virtual void throw_copy() const =0
Member function throw_copy is a pure virtual function which is allows the copying and throwing of the...
const std::string & getTraceback() const
Member function getTraceback returns the exception&#39;s traceback string.
Definition: Exception.hpp:429
Class ExParallel implements the features of a parallel exception. It is a std::string which stores th...
Definition: Exception.hpp:271
ExTemp< std::exception > Exception
Defined in
Definition: Exception.hpp:764
ExParallel & setDescription(const std::string &description)
Member function setDescription sets the value of the exception&#39;s description.
Definition: Exception.hpp:370