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 <cstring>
32 #include <cstdlib>
33 #include <cstdio>
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 
139 /** Constructor.
140  * Constructs a new exception with the given message.
141  * @param format The format of the primary message. Supports the same
142  * arguments as append(). The message is copied and not just referenced.
143  * Thus the memory has to be freed if it is a dynamic string on the heap.
144  */
145 Exception::Exception(const char *format, ...) throw()
146 {
147  messages_mutex = new Mutex();
148 
149  _errno = 0;
150  __type_id = "unknown";
151 
152  messages = NULL;
153  messages_end = NULL;
154  messages_iterator = NULL;
155 
156  if ( format != NULL ) {
157  va_list arg;
158  va_start(arg, format);
159  append_nolock_va(format, arg);
160  va_end(arg);
161  } else {
162  append_nolock("Unnkown Exception");
163  }
164 }
165 
166 
167 /** Constructor.
168  * Constructs a new exception with the given message and errno value. This
169  * is particularly handy when throwing the exception after a function failed
170  * that returns an error code in errno.
171  * @param errnoval error number
172  * @param format The format of the primary message. Supports the same
173  * arguments as append(). The message is copied and not just referenced.
174  * Thus the memory has to be freed if it is a dynamic string on the heap.
175  */
176 Exception::Exception(int errnoval, const char *format, ...) throw()
177 {
178  messages_mutex = new Mutex();
179 
180  _errno = errnoval;
181  __type_id = "unknown";
182 
183  messages = NULL;
184  messages_end = NULL;
185  messages_iterator = NULL;
186 
187  if ( format != NULL ) {
188  va_list arg;
189  va_start(arg, format);
190  char *ext_format;
191  if ( asprintf(&ext_format, "%s (errno: %i, %s)", format, _errno, strerror(_errno)) == -1 ) {
192  append_nolock_va(format, arg);
193  } else {
194  append_nolock_va(ext_format, arg);
195  free(ext_format);
196  }
197  va_end(arg);
198  } else {
199  append_nolock("Exception with errno=%i (%s)", _errno, strerror(_errno));
200  }
201 }
202 
203 
204 /** Copy constructor.
205  * The copy constructor is worth some extra discussion. If you do an exception
206  * by value (which you shouldn't in the first place since this will generate a
207  * copy, only do this if you can't avoid it for some reason. Not if you only
208  * THINK that you can't avoid it) the copy constructor is called. If your catch
209  * statements reads like
210  * @code
211  * try {
212  * ...
213  * } catch (Exception e) {
214  * ...
215  * }
216  * @endcode
217  * then a copy will be created for the catch block. You throw the exception with
218  * something like
219  * @code
220  * throw Exception("Boom");
221  * @endcode
222  * This will create an Exception which is valid in the block where you throw the
223  * exception. Now for the catch block a copy is created. Since the exception
224  * holds a pointer on the heap the implicit copy constructor would just copy
225  * the pointer, not the data. So both exceptions point to the same data (to the
226  * message for the base exception). If now both destructors for the exception
227  * are called they both try to free the very same memory. Of course the second
228  * destructor will cause a disaster. If you are lucky your glibc detectes the
229  * problem an kills the application. If you are not that fortunate you will
230  * cause very strange behaviour of your application.
231  *
232  * In general you should not have to worry about this. But if you choose to have
233  * own storage on the heap using either new, malloc or a method that returns
234  * memory on the heap (like strdup()) you have to write your own copy contructor
235  * and copy the memory area or take care that only one exception frees the memory.
236  * @param exc Exception to copy
237  */
238 Exception::Exception(const Exception &exc) throw()
239 {
240  messages_mutex = new Mutex();
241 
242  messages = NULL;
243  messages_end = NULL;
244  messages_iterator = NULL;
245 
246  _errno = exc._errno;
247  __type_id = exc.__type_id;
248  copy_messages(exc);
249 }
250 
251 
252 /** Constructor for subclasses.
253  * This constructor can be used in subclasses is some processing code is
254  * needed (like sprintf) to assign the message. At least assign the empty
255  * string to the message.
256  */
258 {
259  messages_mutex = new Mutex();
260  _errno = 0;
261  __type_id = "unknown";
262  messages = NULL;
263  messages_end = NULL;
264  messages_iterator = NULL;
265 }
266 
267 
268 /** Destructor. */
270 {
271  message_list_t *msg_this;
273  while ( messages_iterator ) {
274  free(messages_iterator->msg);
275  msg_this = messages_iterator;
277  free(msg_this);
278  }
279  messages = NULL;
280  messages_end = NULL;
281  delete messages_mutex;
282 }
283 
284 
285 /** Set exception type ID.
286  * Set the type ID of this exception.
287  * @param id new type ID, note that this must be a static string which is
288  * guaranteed to exist for the whole lifetime of the exception.
289  * @see Exception::type_id()
290  */
291 void
292 Exception::set_type_id(const char *id)
293 {
294  __type_id = id;
295 }
296 
297 
298 /** Get type ID.
299  * Exceptions can have a type ID. This can be used to avoid having to declare
300  * numerous specific exception sub-classes to different errors, if it is
301  * essential to be able to differentiate them in the exception handling code.
302  * The type ID is a free-form string. It should NOT contain any message, rather
303  * it should be a one-word internal identifier that is never leaked to the user
304  * of the software, i.e. it is not printed anywhere. Note that the ID must be
305  * a static string, which exists for the whole life time of the exception, is
306  * generally not in a dynamically allocated memory (this very exception could
307  * indicate memory shortage). This also makes it thread-safe.
308  * @return type ID
309  */
310 const char *
312 {
313  return __type_id;
314 }
315 
316 
317 /** Prepend messages to the message list.
318  * @param format format of the message to prepend, see printf(3) for details about formatting
319  * options.
320  */
321 void
322 Exception::prepend(const char *format, ...) throw()
323 {
324  // do not append empty messages
325  if (format == NULL) return;
326 
327  va_list arg;
328  va_start(arg, format);
329  messages_mutex->lock();
330  prepend_nolock_va(format, arg);
332  va_end(arg);
333 }
334 
335 
336 /** Append messages to the message list.
337  * @param format format of the message to append, see printf(3) for details about formatting
338  * options.
339  */
340 void
341 Exception::append(const char *format, ...) throw()
342 {
343  // do not append empty messages
344  if (format == NULL) return;
345 
346  va_list arg;
347  va_start(arg, format);
348  messages_mutex->lock();
349  append_nolock_va(format, arg);
351  va_end(arg);
352 }
353 
354 
355 /** Append messages to the message list.
356  * @param format format of the message to append, see printf(3) for details about formatting
357  * options.
358  * @param va va_list with arguments matching the format
359  */
360 void
361 Exception::append_va(const char *format, va_list va) throw()
362 {
363  // do not append empty messages
364  if (format == NULL) return;
365 
366  messages_mutex->lock();
367  append_nolock_va(format, va);
369 }
370 
371 
372 /** Append message that are from another Exception.
373  * @param e Exception to copy messages from
374  */
375 void
376 Exception::append(const Exception &e) throw()
377 {
378  copy_messages(e);
379 }
380 
381 
382 /** Append messages without lock.
383  * this can be used to append messages without locking the mutex if the mutex
384  * has been locked already to append many messages and keep their order intact
385  * and thus to prevent messages to be appended inbetween.
386  * Used for example in copy constructor.
387  * @param format The format of the primary message. Supports the same
388  * arguments as append(). The message is copied and not just referenced.
389  * Thus the memory has to be freed if it is a dynamic string on the heap.
390  */
391 void
392 Exception::append_nolock(const char *format, ...) throw()
393 {
394  va_list arg;
395  va_start(arg, format);
396 
397  char *msg;
398  if ( vasprintf(&msg, format, arg) == -1 ) {
399  msg = strdup(format);
400  }
401 
402  va_end(arg);
403 
404  if ( messages == NULL ) {
405  // This is our first message
406  messages = (message_list_t *)malloc(sizeof(message_list_t));
407  messages->next = NULL;
408  messages->msg = msg;
410  } else {
411  message_list_t *ml = (message_list_t *)malloc(sizeof(message_list_t));
412  ml->next = NULL;
413  ml->msg = msg;
414  messages_end->next = ml;
415  messages_end = ml;
416  }
417 }
418 
419 
420 /** Prepend messages without lock by formatted string.
421  * This can be used to append messages without locking the mutex if the mutex
422  * has been locked already to append many messages and keep their order intact
423  * and thus to prevent messages to be appended inbetween.
424  * Used for example in copy constructor.
425  * @param format format of the message to be appended
426  * @param ap argument va_list for format
427  */
428 void
429 Exception::prepend_nolock_va(const char *format, va_list ap) throw()
430 {
431  char *msg;
432  if ( vasprintf(&msg, format, ap) == -1 ) {
433  msg = strdup(format);
434  }
435 
436  if ( messages == NULL ) {
437  // This is our first message
438  messages = (message_list_t *)malloc(sizeof(message_list_t));
439  messages->next = NULL;
440  messages->msg = msg;
442  } else {
443  message_list_t *ml = (message_list_t *)malloc(sizeof(message_list_t));
444  ml->next = messages;
445  ml->msg = msg;
446  messages = ml;
447  }
448 }
449 
450 
451 /** Append messages without lock by formatted string.
452  * this can be used to append messages without locking the mutex if the mutex
453  * has been locked already to append many messages and keep their order intact
454  * and thus to prevent messages to be appended inbetween.
455  * Used for example in copy constructor.
456  * @param format format of the message to be appended
457  * @param ap argument va_list for format
458  */
459 void
460 Exception::append_nolock_va(const char *format, va_list ap) throw()
461 {
462  char *msg;
463  if ( vasprintf(&msg, format, ap) == -1 ) {
464  msg = strdup(format);
465  }
466 
467  if ( messages == NULL ) {
468  // This is our first message
469  messages = (message_list_t *)malloc(sizeof(message_list_t));
470  messages->next = NULL;
471  messages->msg = msg;
473  } else {
474  message_list_t *ml = (message_list_t *)malloc(sizeof(message_list_t));
475  ml->next = NULL;
476  ml->msg = msg;
477  messages_end->next = ml;
478  messages_end = ml;
479  }
480 }
481 
482 
483 /** Append message without copying.
484  * Can be used in subclasses to append messages that have been allocated
485  * on the heap. Use with extreme care. Do not add constant strings! This would
486  * cause your application to crash since the destructor will try to free all
487  * messages. The message list is not locked.
488  * @param msg Message to append.
489  */
490 void
492 {
493  if ( messages == NULL ) {
494  // This is our first message
495  messages = (message_list_t *)malloc(sizeof(message_list_t));
496  messages->next = NULL;
497  messages->msg = msg;
499  } else {
500  message_list_t *ml = (message_list_t *)malloc(sizeof(message_list_t));
501  ml->next = NULL;
502  ml->msg = msg;
503  messages_end->next = ml;
504  messages_end = ml;
505  }
506 }
507 
508 
509 /** Assign an Exception.
510  * As this is one of the Big Three (see C++ FAQ at
511  * http://www.parashift.com/c++-faq-lite/coding-standards.html#faq-27.10) this
512  * is needed because we already need a copy constructor. Read about the
513  * copy constructor why this is the case.
514  * @see Exception(const Exception &exc)
515  * @param exc The exception with the values to assign to this exception.
516  * @return reference to this object. Allows assignment chaining.
517  */
518 Exception &
519 Exception::operator=(const Exception &exc) throw()
520 {
521  messages_mutex = new Mutex();
522  copy_messages(exc);
523 
524  return *this;
525 }
526 
527 
528 /** Copy messages from given exception.
529  * Copies the messages from exc to this exception.
530  * @param exc Exception to copy messages from.
531  */
532 void
534 {
535  messages_mutex->lock();
536  exc.messages_mutex->lock();
537 
538  // copy messages
539  messages_iterator = exc.messages;
540  while ( messages_iterator ) {
543  }
544 
545  exc.messages_mutex->unlock();
547 }
548 
549 
550 /** This can be used to throw this exception.
551  * This can be used to throw this exception instance. This is a precaution if
552  * it is needed. See C++ FAQ 17.10.
553  */
554 void
556 {
557  throw *this;
558 }
559 
560 
561 /** Prints a backtrace. */
562 void
564 {
565 #ifdef HAVE_EXECINFO
566  void * array[25];
567  int size = backtrace(array, 25);
568  char ** symbols = backtrace_symbols(array, size);
569 
570  printf("Backtrace:\n");
571  for (int i = 0; i < size; ++i) {
572  printf(" %s\n", symbols[i]);
573  }
574 
575  free(symbols);
576 #else
577  printf("Backtrace not available on current system\n");
578 #endif
579 }
580 
581 
582 /** Generate backtrace string.
583  * @return freshly allocated string of backtrace. Free after you are done.
584  */
585 char *
587 {
588 #ifdef HAVE_BACKTRACE
589  void * array[25];
590  int size = backtrace(array, 25);
591  char ** symbols = backtrace_symbols(array, size);
592 
593  size_t total_size = 1; //null termination
594  for (int i = 0; i < size; ++i) {
595  total_size += strlen(symbols[i]) + 1;
596  }
597  char *rv = (char *)calloc(1, total_size);
598  char *r = rv;
599  for (int i = 0; i < size; ++i) {
600  sprintf(r, "%s\n", symbols[i]);
601  r += strlen(symbols[i]);
602  }
603 
604  free(symbols);
605 #else
606  char *rv = strdup("Backtrace not available on current system\n");
607 #endif
608 
609  return rv;
610 }
611 
612 
613 /** Prints trace to stderr.
614  * This prints out a message trace of all messages appended to the exception
615  * in chronological order starting with the oldest (first message appended
616  * via constructor or append(). Output will be sent to stderr.
617  */
618 void
620 {
621  messages_mutex->lock();
622  fprintf(stderr,
623  "=================================================== BEGIN OF EXCEPTION =====\n");
624  if ( messages == NULL ) {
625  fprintf(stderr, "No messages recorded.\n");
626  } else {
628  while ( messages_iterator ) {
629  fprintf(stderr, "%s\n", messages_iterator->msg);
631  }
632  }
633  fprintf(stderr,
634  "=================================================== END OF EXCEPTION =======\n");
636 }
637 
638 
639 /** Get errno.
640  * @return error number, may be 0 if not set
641  */
642 int
644 {
645  return _errno;
646 }
647 
648 
649 /** Get primary string.
650  * Messages are stored in a list. The first entry in this list is called primary
651  * message. This is why it is important to have a meaningful first message!
652  * @return Returns a constant char pointer with the message. The message is
653  * private to the exception and may not be modified or freed (hence const)
654  * If no message has been set "Unknown error" is returned. This method may be
655  * overidden by other exceptions.
656  * This method is also called by the runtime system if the exception was not
657  * caught and resulted in a program termination.
658  * @return string describing the general cause of the current error
659  */
660 const char *
661 Exception::what() const throw()
662 {
663 #ifdef HAVE_EXECINFO
664  print_backtrace();
665 #endif
666  if ( messages != NULL ) {
667  return messages->msg;
668  } else {
669  return "Unknown error";
670  }
671 }
672 
673 
674 /** Get primary string (does not implicitly print the back trace).
675  * Messages are stored in a list. The first entry in this list is called primary
676  * message. This is why it is important to have a meaningful first message!
677  * @return Returns a constant char pointer with the message. The message is
678  * private to the exception and may not be modified or freed (hence const)
679  * If no message has been set "Unknown error" is returned. This method may be
680  * overidden by other exceptions.
681  * This method is also called by the runtime system if the exception was not
682  * caught and resulted in a program termination.
683  * @return string describing the general cause of the current error
684  */
685 const char *
687 {
688  if ( messages != NULL ) {
689  return messages->msg;
690  } else {
691  return "Unknown error";
692  }
693 }
694 
695 
696 /** Get iterator for messages.
697  * @return iterator for messages
698  */
701 {
703  return i;
704 }
705 
706 
707 /** @class Exception::iterator <core/exception.h>
708  * Message iterator for exceptions.
709  * This iterator allows for iterating over all messages carried by an Exception.
710  * @author Tim Niemueller
711  */
712 
713 /** Get end iterator for messages.
714  * @return end iterator for messages.
715  */
717 Exception::end() throw()
718 {
720  return i;
721 }
722 
723 
724 /** Constructor.
725  * @param message_list list of messages, will be used unlocked so use
726  * with care.
727  */
729 {
730  mlist = message_list;
731 }
732 
733 
734 /** Plain constructor.
735  * Creates a new invalid iterator (same as Exception::end()).
736  */
738 {
739  this->mlist = NULL;
740 }
741 
742 
743 /** Copy constructor.
744  * @param i iterator to copy
745  */
747 {
748  this->mlist = i.mlist;
749 }
750 
751 
752 /** Prefix ++ operator.
753  * @return reference to this iterator after advancing.
754  */
757 {
758  if ( mlist != NULL ) {
759  mlist = mlist->next;
760  }
761  return *this;
762 }
763 
764 
765 /** Postfix ++ operator.
766  * @param inc used to denote postfix operator
767  * @return copy of iterator before advancing.
768  */
771 {
772  iterator i(mlist);
773  if ( mlist != NULL ) {
774  mlist = mlist->next;
775  }
776  return i;
777 }
778 
779 
780 /** Check equality.
781  * @param i iterator to compare to
782  * @return true, if iterators point to the same message, false otherwise
783  */
784 bool
786 {
787  return (mlist == i.mlist);
788 }
789 
790 
791 /** Check inequality.
792  * @param i iterator to compare to
793  * @return true, if iterators point to different messages, false otherwise
794  */
795 bool
797 {
798  return (mlist != i.mlist);
799 }
800 
801 
802 /** Get current message.
803  * Get message at current position. Returns NULL for the invalid ieterator.
804  * @return message or NULL if iterator is invalid
805  */
806 const char *
808 {
809  if ( mlist != NULL ) {
810  return mlist->msg;
811  } else {
812  return NULL;
813  }
814 }
815 
816 
817 /** Assignment operator.
818  * @param i iterator to assign to this iterator.
819  * @return reference to this iterator.
820  */
823 {
824  this->mlist = i.mlist;
825  return *this;
826 }
827 
828 
829 } // end namespace fawkes
message_list_t * messages_end
Pointer that points to the very last message.
Definition: exception.h:108
const char * operator*() const
Get current message.
Definition: exception.cpp:807
Mutex * messages_mutex
Mutex to protect operations on messages list.
Definition: exception.h:109
int get_errno()
Get errno.
Definition: exception.cpp:643
void print_backtrace() const
Prints a backtrace.
Definition: exception.cpp:563
Fawkes library namespace.
void unlock()
Unlock the mutex.
Definition: mutex.cpp:135
Exception()
Constructor for subclasses.
Definition: exception.cpp:257
virtual void raise()
This can be used to throw this exception.
Definition: exception.cpp:555
virtual const char * what() const
Get primary string.
Definition: exception.cpp:661
int _errno
Error number, should be used if the error was caused by a method that supplies errno.
Definition: exception.h:111
void prepend_nolock_va(const char *format, va_list va)
Prepend messages without lock by formatted string.
Definition: exception.cpp:429
Message iterator for exceptions.
Definition: exception.h:72
virtual ~Exception()
Destructor.
Definition: exception.cpp:269
iterator()
Plain constructor.
Definition: exception.cpp:737
iterator end()
Get end iterator for messages.
Definition: exception.cpp:717
iterator & operator++()
Prefix ++ operator.
Definition: exception.cpp:756
Base class for exceptions in Fawkes.
Definition: exception.h:36
void append_nolock_va(const char *format, va_list va)
Append messages without lock by formatted string.
Definition: exception.cpp:460
void append_nolock(const char *format,...)
Append messages without lock.
Definition: exception.cpp:392
message_list_t * messages
List of messages.
Definition: exception.h:106
const char * type_id() const
Get type ID.
Definition: exception.cpp:311
void prepend(const char *format,...)
Prepend messages to the message list.
Definition: exception.cpp:322
bool operator!=(const iterator &i) const
Check inequality.
Definition: exception.cpp:796
message_list_t * messages_iterator
Iterator to iterate over messages.
Definition: exception.h:107
iterator begin()
Get iterator for messages.
Definition: exception.cpp:700
virtual const char * what_no_backtrace() const
Get primary string (does not implicitly print the back trace).
Definition: exception.cpp:686
void append_va(const char *format, va_list va)
Append messages to the message list.
Definition: exception.cpp:361
Internal exception message list.
Definition: exception.h:65
void print_trace()
Prints trace to stderr.
Definition: exception.cpp:619
iterator & operator=(const iterator &i)
Assignment operator.
Definition: exception.cpp:822
void set_type_id(const char *id)
Set exception type ID.
Definition: exception.cpp:292
message_list_t * next
pointer to next element, NULL if last element
Definition: exception.h:66
void lock()
Lock this mutex.
Definition: mutex.cpp:89
void copy_messages(const Exception &exc)
Copy messages from given exception.
Definition: exception.cpp:533
Exception & operator=(const Exception &exc)
Assign an Exception.
Definition: exception.cpp:519
Mutex mutual exclusion lock.
Definition: mutex.h:32
bool operator==(const iterator &i) const
Check equality.
Definition: exception.cpp:785
void append_nolock_nocopy(char *msg)
Append message without copying.
Definition: exception.cpp:491
char * generate_backtrace() const
Generate backtrace string.
Definition: exception.cpp:586
void append(const char *format,...)
Append messages to the message list.
Definition: exception.cpp:341
char * msg
pointer to message, may not be NULL, will be freed in dtor
Definition: exception.h:67