Fawkes API  Fawkes Development Version
exception.cpp
1 
2 /***************************************************************************
3  * exception.cpp - basic exception
4  *
5  * Generated: Thu Feb 09 13:04:45 2006 (from FireVision)
6  * Copyright 2005-2006 Tim Niemueller [www.niemueller.de]
7  *
8  ****************************************************************************/
9 
10 /* This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version. A runtime exception applies to
14  * this software (see LICENSE.GPL_WRE file mentioned below for details).
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU Library General Public License for more details.
20  *
21  * Read the full text in the LICENSE.GPL_WRE file in the doc directory.
22  */
23 
24 #include <core/exception.h>
25 #include <core/threading/mutex.h>
26 
27 #ifndef _GNU_SOURCE
28 # define _GNU_SOURCE
29 #endif
30 
31 #include <cstdio>
32 #include <cstdlib>
33 #include <cstring>
34 #ifdef HAVE_EXECINFO
35 # include <execinfo.h>
36 #endif
37 
38 namespace fawkes {
39 
40 /** @class Exception core/exception.h
41  * Base class for exceptions in Fawkes.
42  * Exceptions are a good way to handle errors. If you choose to use
43  * exceptions use derivates of this class so that there is a unified way of
44  * handling errors in Fawkes. Do <i>not</i> throw an arbitrary class such as
45  * a string or integer as this is hard to handle.
46  *
47  * For your exceptions in general you only need to override the constructor
48  * and call the Exception constructor with the appropriate message. In
49  * cases where more information is needed about the error add appropriate
50  * handlers.
51  *
52  * In most cases it is bad to just throw an Exception like this:
53  *
54  * @code
55  * if ( error_condition ) {
56  * throw Exception("Out of memory");
57  * }
58  * @endcode
59  *
60  * Rather you should explicitly subclass Exception appropriately. For the
61  * above example you could have something like this as exception class:
62  *
63  * @code
64  * class OutOfMemException : public Exception
65  * {
66  * public:
67  * OutOfMemoryException() : Exception("Out of memory") {}
68  * }
69  * @endcode
70  *
71  * And in your handling code you throw a OutOfMemoryException. This is
72  * especially useful if it is possible to throw several different exceptions.
73  * If the message was different you would have to parse the string for
74  * the exact error. This can be avoided if you just catch different
75  * exceptions. This is also useful if the Exception is not catched explicitly
76  * as this will printout the name of the exception class thrown just before
77  * exiting the program. And reading something like
78  * "terminate called after throwing an instance of 'OutOfMemoryException'"
79  * makes it a lot easier to spot the problem.
80  *
81  * Exceptions should be catched by reference like this:
82  * @code
83  * try {
84  * some_operation();
85  * } catch (OutOfMemoryException &e) {
86  * std::cout << e.c_str() << std::endl;
87  * error_handling();
88  * }
89  * @endcode
90  *
91  * Messages are stored as list. The first message however is called the
92  * primary message and it should contain as much information as available.
93  * This message is printed on the screen if the application crashes with an
94  * unhandled exception. So having meaningful content here means that the
95  * error can be traced more easily.
96  *
97  * You can utilize the list feature by adding appropriate information
98  * through appropriate try/catch statements. This way you can
99  * build information path ways that will help to debug your software. Use
100  * block like this to append information:
101  * @code
102  * try {
103  * potentially_failing();
104  * } catch {MyException &e) {
105  * e.append("info where exception happened");
106  * throw; // re-throw exception
107  * }
108  * @endcode
109  * This is especially useful if the exception may occur at several different
110  * places and it cannot be fixed where it happens.
111  *
112  *
113  * @see example_exception.cpp
114  * @ingroup FCL
115  * @ingroup Exceptions
116  *
117  * @author Tim Niemueller
118  */
119 /** @var Exception::messages
120  * List of messages. Should not be NULL. Messages are append with append().
121  * Using a custom list to avoid including STL stuff in this core file.
122  * @see append()
123  */
124 /** @var Exception::messages_iterator
125  * Iterator to iterate over messages
126  */
127 /** @var Exception::messages_end
128  * Pointer that points to the very last message. Used for fast appending.
129  */
130 /** @var Exception::messages_mutex
131  * Mutex to protect operations on messages list.
132  */
133 /** @var Exception::_errno
134  * Error number, should be used if the error was caused by a method that supplies
135  * errno.
136  */
137 
138 /** Constructor.
139  * Constructs a new exception with the given message.
140  * @param format The format of the primary message. Supports the same
141  * arguments as append(). The message is copied and not just referenced.
142  * Thus the memory has to be freed if it is a dynamic string on the heap.
143  */
144 Exception::Exception(const char *format, ...) throw()
145 {
146  messages_mutex = new Mutex();
147 
148  _errno = 0;
149  type_id_ = "unknown";
150 
151  messages = NULL;
152  messages_end = NULL;
153  messages_iterator = NULL;
154 
155  if (format != NULL) {
156  va_list arg;
157  va_start(arg, format);
158  append_nolock_va(format, arg);
159  va_end(arg);
160  } else {
161  append_nolock("Unnkown Exception");
162  }
163 }
164 
165 /** Constructor.
166  * Constructs a new exception with the given message and errno value. This
167  * is particularly handy when throwing the exception after a function failed
168  * that returns an error code in errno.
169  * @param errnoval error number
170  * @param format The format of the primary message. Supports the same
171  * arguments as append(). The message is copied and not just referenced.
172  * Thus the memory has to be freed if it is a dynamic string on the heap.
173  */
174 Exception::Exception(int errnoval, const char *format, ...) throw()
175 {
176  messages_mutex = new Mutex();
177 
178  _errno = errnoval;
179  type_id_ = "unknown";
180 
181  messages = NULL;
182  messages_end = NULL;
183  messages_iterator = NULL;
184 
185  if (format != NULL) {
186  va_list arg;
187  va_start(arg, format);
188  char *ext_format;
189  if (asprintf(&ext_format, "%s (errno: %i, %s)", format, _errno, strerror(_errno)) == -1) {
190  append_nolock_va(format, arg);
191  } else {
192  append_nolock_va(ext_format, arg);
193  free(ext_format);
194  }
195  va_end(arg);
196  } else {
197  append_nolock("Exception with errno=%i (%s)", _errno, strerror(_errno));
198  }
199 }
200 
201 /** Copy constructor.
202  * The copy constructor is worth some extra discussion. If you do an exception
203  * by value (which you shouldn't in the first place since this will generate a
204  * copy, only do this if you can't avoid it for some reason. Not if you only
205  * THINK that you can't avoid it) the copy constructor is called. If your catch
206  * statements reads like
207  * @code
208  * try {
209  * ...
210  * } catch (Exception e) {
211  * ...
212  * }
213  * @endcode
214  * then a copy will be created for the catch block. You throw the exception with
215  * something like
216  * @code
217  * throw Exception("Boom");
218  * @endcode
219  * This will create an Exception which is valid in the block where you throw the
220  * exception. Now for the catch block a copy is created. Since the exception
221  * holds a pointer on the heap the implicit copy constructor would just copy
222  * the pointer, not the data. So both exceptions point to the same data (to the
223  * message for the base exception). If now both destructors for the exception
224  * are called they both try to free the very same memory. Of course the second
225  * destructor will cause a disaster. If you are lucky your glibc detectes the
226  * problem an kills the application. If you are not that fortunate you will
227  * cause very strange behaviour of your application.
228  *
229  * In general you should not have to worry about this. But if you choose to have
230  * own storage on the heap using either new, malloc or a method that returns
231  * memory on the heap (like strdup()) you have to write your own copy contructor
232  * and copy the memory area or take care that only one exception frees the memory.
233  * @param exc Exception to copy
234  */
235 Exception::Exception(const Exception &exc) throw()
236 {
237  messages_mutex = new Mutex();
238 
239  messages = NULL;
240  messages_end = NULL;
241  messages_iterator = NULL;
242 
243  _errno = exc._errno;
244  type_id_ = exc.type_id_;
245  copy_messages(exc);
246 }
247 
248 /** Constructor for subclasses.
249  * This constructor can be used in subclasses is some processing code is
250  * needed (like sprintf) to assign the message. At least assign the empty
251  * string to the message.
252  */
254 {
255  messages_mutex = new Mutex();
256  _errno = 0;
257  type_id_ = "unknown";
258  messages = NULL;
259  messages_end = NULL;
260  messages_iterator = NULL;
261 }
262 
263 /** Destructor. */
265 {
266  message_list_t *msg_this;
268  while (messages_iterator) {
269  free(messages_iterator->msg);
270  msg_this = messages_iterator;
272  free(msg_this);
273  }
274  messages = NULL;
275  messages_end = NULL;
276  delete messages_mutex;
277 }
278 
279 /** Set exception type ID.
280  * Set the type ID of this exception.
281  * @param id new type ID, note that this must be a static string which is
282  * guaranteed to exist for the whole lifetime of the exception.
283  * @see Exception::type_id()
284  */
285 void
286 Exception::set_type_id(const char *id)
287 {
288  type_id_ = id;
289 }
290 
291 /** Get type ID.
292  * Exceptions can have a type ID. This can be used to avoid having to declare
293  * numerous specific exception sub-classes to different errors, if it is
294  * essential to be able to differentiate them in the exception handling code.
295  * The type ID is a free-form string. It should NOT contain any message, rather
296  * it should be a one-word internal identifier that is never leaked to the user
297  * of the software, i.e. it is not printed anywhere. Note that the ID must be
298  * a static string, which exists for the whole life time of the exception, is
299  * generally not in a dynamically allocated memory (this very exception could
300  * indicate memory shortage). This also makes it thread-safe.
301  * @return type ID
302  */
303 const char *
305 {
306  return type_id_;
307 }
308 
309 /** Prepend messages to the message list.
310  * @param format format of the message to prepend, see printf(3) for details about formatting
311  * options.
312  */
313 void
314 Exception::prepend(const char *format, ...) throw()
315 {
316  // do not append empty messages
317  if (format == NULL)
318  return;
319 
320  va_list arg;
321  va_start(arg, format);
322  messages_mutex->lock();
323  prepend_nolock_va(format, arg);
325  va_end(arg);
326 }
327 
328 /** Append messages to the message list.
329  * @param format format of the message to append, see printf(3) for details about formatting
330  * options.
331  */
332 void
333 Exception::append(const char *format, ...) throw()
334 {
335  // do not append empty messages
336  if (format == NULL)
337  return;
338 
339  va_list arg;
340  va_start(arg, format);
341  messages_mutex->lock();
342  append_nolock_va(format, arg);
344  va_end(arg);
345 }
346 
347 /** Append messages to the message list.
348  * @param format format of the message to append, see printf(3) for details about formatting
349  * options.
350  * @param va va_list with arguments matching the format
351  */
352 void
353 Exception::append_va(const char *format, va_list va) throw()
354 {
355  // do not append empty messages
356  if (format == NULL)
357  return;
358 
359  messages_mutex->lock();
360  append_nolock_va(format, va);
361  messages_mutex->unlock();
362 }
363 
364 /** Append message that are from another Exception.
365  * @param e Exception to copy messages from
366  */
367 void
368 Exception::append(const Exception &e) throw()
369 {
370  copy_messages(e);
371 }
372 
373 /** Append messages without lock.
374  * this can be used to append messages without locking the mutex if the mutex
375  * has been locked already to append many messages and keep their order intact
376  * and thus to prevent messages to be appended inbetween.
377  * Used for example in copy constructor.
378  * @param format The format of the primary message. Supports the same
379  * arguments as append(). The message is copied and not just referenced.
380  * Thus the memory has to be freed if it is a dynamic string on the heap.
381  */
382 void
383 Exception::append_nolock(const char *format, ...) throw()
384 {
385  va_list arg;
386  va_start(arg, format);
387 
388  char *msg;
389  if (vasprintf(&msg, format, arg) == -1) {
390  msg = strdup(format);
391  }
392 
393  va_end(arg);
394 
395  if (messages == NULL) {
396  // This is our first message
397  messages = (message_list_t *)malloc(sizeof(message_list_t));
398  messages->next = NULL;
399  messages->msg = msg;
401  } else {
402  message_list_t *ml = (message_list_t *)malloc(sizeof(message_list_t));
403  ml->next = NULL;
404  ml->msg = msg;
405  messages_end->next = ml;
406  messages_end = ml;
407  }
408 }
409 
410 /** Prepend messages without lock by formatted string.
411  * This can be used to append messages without locking the mutex if the mutex
412  * has been locked already to append many messages and keep their order intact
413  * and thus to prevent messages to be appended inbetween.
414  * Used for example in copy constructor.
415  * @param format format of the message to be appended
416  * @param ap argument va_list for format
417  */
418 void
419 Exception::prepend_nolock_va(const char *format, va_list ap) throw()
420 {
421  char *msg;
422  if (vasprintf(&msg, format, ap) == -1) {
423  msg = strdup(format);
424  }
425 
426  if (messages == NULL) {
427  // This is our first message
428  messages = (message_list_t *)malloc(sizeof(message_list_t));
429  messages->next = NULL;
430  messages->msg = msg;
431  messages_end = messages;
432  } else {
433  message_list_t *ml = (message_list_t *)malloc(sizeof(message_list_t));
434  ml->next = messages;
435  ml->msg = msg;
436  messages = ml;
437  }
438 }
439 
440 /** Append messages without lock by formatted string.
441  * this can be used to append messages without locking the mutex if the mutex
442  * has been locked already to append many messages and keep their order intact
443  * and thus to prevent messages to be appended inbetween.
444  * Used for example in copy constructor.
445  * @param format format of the message to be appended
446  * @param ap argument va_list for format
447  */
448 void
449 Exception::append_nolock_va(const char *format, va_list ap) throw()
450 {
451  char *msg;
452  if (vasprintf(&msg, format, ap) == -1) {
453  msg = strdup(format);
454  }
455 
456  if (messages == NULL) {
457  // This is our first message
458  messages = (message_list_t *)malloc(sizeof(message_list_t));
459  messages->next = NULL;
460  messages->msg = msg;
461  messages_end = messages;
462  } else {
463  message_list_t *ml = (message_list_t *)malloc(sizeof(message_list_t));
464  ml->next = NULL;
465  ml->msg = msg;
466  messages_end->next = ml;
467  messages_end = ml;
468  }
469 }
470 
471 /** Append message without copying.
472  * Can be used in subclasses to append messages that have been allocated
473  * on the heap. Use with extreme care. Do not add constant strings! This would
474  * cause your application to crash since the destructor will try to free all
475  * messages. The message list is not locked.
476  * @param msg Message to append.
477  */
478 void
480 {
481  if (messages == NULL) {
482  // This is our first message
483  messages = (message_list_t *)malloc(sizeof(message_list_t));
484  messages->next = NULL;
485  messages->msg = msg;
486  messages_end = messages;
487  } else {
488  message_list_t *ml = (message_list_t *)malloc(sizeof(message_list_t));
489  ml->next = NULL;
490  ml->msg = msg;
491  messages_end->next = ml;
492  messages_end = ml;
493  }
494 }
495 
496 /** Assign an Exception.
497  * As this is one of the Big Three (see C++ FAQ at
498  * http://www.parashift.com/c++-faq-lite/coding-standards.html#faq-27.10) this
499  * is needed because we already need a copy constructor. Read about the
500  * copy constructor why this is the case.
501  * @see Exception(const Exception &exc)
502  * @param exc The exception with the values to assign to this exception.
503  * @return reference to this object. Allows assignment chaining.
504  */
505 Exception &
506 Exception::operator=(const Exception &exc) throw()
507 {
508  messages_mutex = new Mutex();
509  copy_messages(exc);
510 
511  return *this;
512 }
513 
514 /** Copy messages from given exception.
515  * Copies the messages from exc to this exception.
516  * @param exc Exception to copy messages from.
517  */
518 void
520 {
521  messages_mutex->lock();
522  exc.messages_mutex->lock();
523 
524  // copy messages
525  messages_iterator = exc.messages;
526  while (messages_iterator) {
527  append_nolock(messages_iterator->msg);
528  messages_iterator = messages_iterator->next;
529  }
530 
531  exc.messages_mutex->unlock();
532  messages_mutex->unlock();
533 }
534 
535 /** This can be used to throw this exception.
536  * This can be used to throw this exception instance. This is a precaution if
537  * it is needed. See C++ FAQ 17.10.
538  */
539 void
541 {
542  throw *this;
543 }
544 
545 /** Prints a backtrace. */
546 void
548 {
549 #ifdef HAVE_EXECINFO
550  void * array[25];
551  int size = backtrace(array, 25);
552  char **symbols = backtrace_symbols(array, size);
553 
554  printf("Backtrace:\n");
555  for (int i = 0; i < size; ++i) {
556  printf(" %s\n", symbols[i]);
557  }
558 
559  free(symbols);
560 #else
561  printf("Backtrace not available on current system\n");
562 #endif
563 }
564 
565 /** Generate backtrace string.
566  * @return freshly allocated string of backtrace. Free after you are done.
567  */
568 char *
570 {
571 #ifdef HAVE_BACKTRACE
572  void * array[25];
573  int size = backtrace(array, 25);
574  char **symbols = backtrace_symbols(array, size);
575 
576  size_t total_size = 1; //null termination
577  for (int i = 0; i < size; ++i) {
578  total_size += strlen(symbols[i]) + 1;
579  }
580  char *rv = (char *)calloc(1, total_size);
581  char *r = rv;
582  for (int i = 0; i < size; ++i) {
583  sprintf(r, "%s\n", symbols[i]);
584  r += strlen(symbols[i]);
585  }
586 
587  free(symbols);
588 #else
589  char *rv = strdup("Backtrace not available on current system\n");
590 #endif
591 
592  return rv;
593 }
594 
595 /** Prints trace to stderr.
596  * This prints out a message trace of all messages appended to the exception
597  * in chronological order starting with the oldest (first message appended
598  * via constructor or append(). Output will be sent to stderr.
599  */
600 void
602 {
603  messages_mutex->lock();
604  fprintf(stderr, "=================================================== BEGIN OF EXCEPTION =====\n");
605  if (messages == NULL) {
606  fprintf(stderr, "No messages recorded.\n");
607  } else {
609  while (messages_iterator) {
610  fprintf(stderr, "%s\n", messages_iterator->msg);
612  }
613  }
614  fprintf(stderr, "=================================================== END OF EXCEPTION =======\n");
616 }
617 
618 /** Get errno.
619  * @return error number, may be 0 if not set
620  */
621 int
623 {
624  return _errno;
625 }
626 
627 /** Get primary string.
628  * Messages are stored in a list. The first entry in this list is called primary
629  * message. This is why it is important to have a meaningful first message!
630  * @return Returns a constant char pointer with the message. The message is
631  * private to the exception and may not be modified or freed (hence const)
632  * If no message has been set "Unknown error" is returned. This method may be
633  * overidden by other exceptions.
634  * This method is also called by the runtime system if the exception was not
635  * caught and resulted in a program termination.
636  * @return string describing the general cause of the current error
637  */
638 const char *
639 Exception::what() const throw()
640 {
641 #ifdef HAVE_EXECINFO
642  print_backtrace();
643 #endif
644  if (messages != NULL) {
645  return messages->msg;
646  } else {
647  return "Unknown error";
648  }
649 }
650 
651 /** Get primary string (does not implicitly print the back trace).
652  * Messages are stored in a list. The first entry in this list is called primary
653  * message. This is why it is important to have a meaningful first message!
654  * @return Returns a constant char pointer with the message. The message is
655  * private to the exception and may not be modified or freed (hence const)
656  * If no message has been set "Unknown error" is returned. This method may be
657  * overidden by other exceptions.
658  * This method is also called by the runtime system if the exception was not
659  * caught and resulted in a program termination.
660  * @return string describing the general cause of the current error
661  */
662 const char *
664 {
665  if (messages != NULL) {
666  return messages->msg;
667  } else {
668  return "Unknown error";
669  }
670 }
671 
672 /** Get iterator for messages.
673  * @return iterator for messages
674  */
677 {
679  return i;
680 }
681 
682 /** @class Exception::iterator <core/exception.h>
683  * Message iterator for exceptions.
684  * This iterator allows for iterating over all messages carried by an Exception.
685  * @author Tim Niemueller
686  */
687 
688 /** Get end iterator for messages.
689  * @return end iterator for messages.
690  */
692 Exception::end() throw()
693 {
695  return i;
696 }
697 
698 /** Constructor.
699  * @param message_list list of messages, will be used unlocked so use
700  * with care.
701  */
702 Exception::iterator::iterator(message_list_t *message_list)
703 {
704  mlist = message_list;
705 }
706 
707 /** Plain constructor.
708  * Creates a new invalid iterator (same as Exception::end()).
709  */
711 {
712  this->mlist = NULL;
713 }
714 
715 /** Copy constructor.
716  * @param i iterator to copy
717  */
719 {
720  this->mlist = i.mlist;
721 }
722 
723 /** Prefix ++ operator.
724  * @return reference to this iterator after advancing.
725  */
728 {
729  if (mlist != NULL) {
730  mlist = mlist->next;
731  }
732  return *this;
733 }
734 
735 /** Postfix ++ operator.
736  * @param inc used to denote postfix operator
737  * @return copy of iterator before advancing.
738  */
741 {
742  iterator i(mlist);
743  if (mlist != NULL) {
744  mlist = mlist->next;
745  }
746  return i;
747 }
748 
749 /** Check equality.
750  * @param i iterator to compare to
751  * @return true, if iterators point to the same message, false otherwise
752  */
753 bool
755 {
756  return (mlist == i.mlist);
757 }
758 
759 /** Check inequality.
760  * @param i iterator to compare to
761  * @return true, if iterators point to different messages, false otherwise
762  */
763 bool
765 {
766  return (mlist != i.mlist);
767 }
768 
769 /** Get current message.
770  * Get message at current position. Returns NULL for the invalid ieterator.
771  * @return message or NULL if iterator is invalid
772  */
774 {
775  if (mlist != NULL) {
776  return mlist->msg;
777  } else {
778  return NULL;
779  }
780 }
781 
782 /** Assignment operator.
783  * @param i iterator to assign to this iterator.
784  * @return reference to this iterator.
785  */
788 {
789  this->mlist = i.mlist;
790  return *this;
791 }
792 
793 } // end namespace fawkes
message_list_t * messages_end
Pointer that points to the very last message.
Definition: exception.h:110
const char * operator*() const
Get current message.
Definition: exception.cpp:773
Mutex * messages_mutex
Mutex to protect operations on messages list.
Definition: exception.h:111
int get_errno()
Get errno.
Definition: exception.cpp:622
void print_backtrace() const
Prints a backtrace.
Definition: exception.cpp:547
Fawkes library namespace.
void unlock()
Unlock the mutex.
Definition: mutex.cpp:131
Exception()
Constructor for subclasses.
Definition: exception.cpp:253
virtual void raise()
This can be used to throw this exception.
Definition: exception.cpp:540
virtual const char * what() const
Get primary string.
Definition: exception.cpp:639
int _errno
Error number, should be used if the error was caused by a method that supplies errno.
Definition: exception.h:113
void prepend_nolock_va(const char *format, va_list va)
Prepend messages without lock by formatted string.
Definition: exception.cpp:419
Message iterator for exceptions.
Definition: exception.h:72
virtual ~Exception()
Destructor.
Definition: exception.cpp:264
iterator()
Plain constructor.
Definition: exception.cpp:710
iterator end()
Get end iterator for messages.
Definition: exception.cpp:692
iterator & operator++()
Prefix ++ operator.
Definition: exception.cpp:727
Base class for exceptions in Fawkes.
Definition: exception.h:35
void append_nolock_va(const char *format, va_list va)
Append messages without lock by formatted string.
Definition: exception.cpp:449
void append_nolock(const char *format,...)
Append messages without lock.
Definition: exception.cpp:383
message_list_t * messages
List of messages.
Definition: exception.h:108
const char * type_id() const
Get type ID.
Definition: exception.cpp:304
void prepend(const char *format,...)
Prepend messages to the message list.
Definition: exception.cpp:314
bool operator!=(const iterator &i) const
Check inequality.
Definition: exception.cpp:764
message_list_t * messages_iterator
Iterator to iterate over messages.
Definition: exception.h:109
iterator begin()
Get iterator for messages.
Definition: exception.cpp:676
virtual const char * what_no_backtrace() const
Get primary string (does not implicitly print the back trace).
Definition: exception.cpp:663
void append_va(const char *format, va_list va)
Append messages to the message list.
Definition: exception.cpp:353
Internal exception message list.
Definition: exception.h:64
void print_trace()
Prints trace to stderr.
Definition: exception.cpp:601
iterator & operator=(const iterator &i)
Assignment operator.
Definition: exception.cpp:787
void set_type_id(const char *id)
Set exception type ID.
Definition: exception.cpp:286
message_list_t * next
pointer to next element, NULL if last element
Definition: exception.h:66
void lock()
Lock this mutex.
Definition: mutex.cpp:87
void copy_messages(const Exception &exc)
Copy messages from given exception.
Definition: exception.cpp:519
Exception & operator=(const Exception &exc)
Assign an Exception.
Definition: exception.cpp:506
Mutex mutual exclusion lock.
Definition: mutex.h:32
bool operator==(const iterator &i) const
Check equality.
Definition: exception.cpp:754
void append_nolock_nocopy(char *msg)
Append message without copying.
Definition: exception.cpp:479
char * generate_backtrace() const
Generate backtrace string.
Definition: exception.cpp:569
void append(const char *format,...)
Append messages to the message list.
Definition: exception.cpp:333
char * msg
pointer to message, may not be NULL, will be freed in dtor
Definition: exception.h:67