1 /* ex - Exception Handling */
3 /* Copyright (c) 2005-2010 The SimGrid team */
4 /* Copyright (c) 2002-2004 Ralf S. Engelschall <rse@engelschall.com> */
5 /* Copyright (c) 2002-2004 The OSSP Project <http://www.ossp.org/> */
6 /* Copyright (c) 2002-2004 Cable & Wireless <http://www.cw.com/> */
7 /* All rights reserved. */
9 /* This code is inspirated from the OSSP version (as retrieved back in 2004)*/
10 /* It was heavily modified to fit the SimGrid framework. */
12 /* The OSSP version has the following copyright notice:
13 ** OSSP ex - Exception Handling
14 ** Copyright (c) 2002-2004 Ralf S. Engelschall <rse@engelschall.com>
15 ** Copyright (c) 2002-2004 The OSSP Project <http://www.ossp.org/>
16 ** Copyright (c) 2002-2004 Cable & Wireless <http://www.cw.com/>
18 ** This file is part of OSSP ex, an exception handling library
19 ** which can be found at http://www.ossp.org/pkg/lib/ex/.
21 ** Permission to use, copy, modify, and distribute this software for
22 ** any purpose with or without fee is hereby granted, provided that
23 ** the above copyright notice and this permission notice appear in all
26 ** THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESSED OR IMPLIED
27 ** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
28 ** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29 ** IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
30 ** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
33 ** USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
34 ** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
35 ** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
36 ** OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 /* The extensions made for the SimGrid project can either be distributed */
41 /* under the same license, or under the LGPL v2.1 */
46 #include "portable.h" /* execinfo when available */
49 #include "xbt/module.h" /* xbt_binary_name */
50 #include "xbt_modinter.h" /* backtrace initialization headers */
51 #include "xbt/synchro.h" /* xbt_thread_self */
53 #include "gras/Virtu/virtu_interface.h" /* gras_os_myname */
54 #include "xbt/ex_interface.h"
57 #if defined(HAVE_EXECINFO_H) && defined(HAVE_POPEN) && defined(ADDR2LINE)
58 # define HAVE_BACKTRACE 1 /* Hello linux box */
61 #if defined(_XBT_WIN32) && defined(_M_IX86) && !defined(__GNUC__)
62 # define HAVE_BACKTRACE 1 /* Hello x86 windows box */
66 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(xbt_ex, xbt, "Exception mecanism");
68 /* default __ex_ctx callback function */
69 ex_ctx_t *__xbt_ex_ctx_default(void)
71 /* Don't scream: this is a default which is never used (so, yes,
72 there is one setjump container by running entity).
74 This default gets overriden in xbt/xbt_os_thread.c so that it works in
75 real life and in simulation when using threads to implement the simulation
76 processes (ie, with pthreads and on windows).
78 It also gets overriden in xbt/context.c when using ucontextes (as well as
79 in Java for now, but after the java overhaul, it will get cleaned out)
81 static ex_ctx_t ctx = XBT_CTX_INITIALIZER;
86 /* Change raw libc symbols to file names and line numbers */
87 void xbt_ex_setup_backtrace(xbt_ex_t * e);
89 void xbt_backtrace_display(xbt_ex_t * e)
91 xbt_ex_setup_backtrace(e);
95 fprintf(stderr, "(backtrace not set)\n");
99 fprintf(stderr, "Backtrace (displayed in thread %p):\n",
100 (void *) xbt_thread_self());
101 for (i = 1; i < e->used; i++) /* no need to display "xbt_display_backtrace" */
102 fprintf(stderr, "---> %s\n", e->bt_strings[i] + 4);
105 /* don't fool xbt_ex_free with uninitialized msg field */
111 ERROR0("No backtrace on this arch");
115 /** \brief show the backtrace of the current point (lovely while debuging) */
116 void xbt_backtrace_display_current(void)
119 xbt_backtrace_current(&e);
120 xbt_backtrace_display(&e);
123 #if defined(HAVE_EXECINFO_H) && defined(HAVE_POPEN) && defined(ADDR2LINE)
124 # include "backtrace_linux.c"
125 #elif (defined(_XBT_WIN32) && defined (_M_IX86)) && !defined(__GNUC__)
126 # include "backtrace_windows.c"
128 # include "backtrace_dummy.c"
131 /** @brief shows an exception content and the associated stack if available */
132 void xbt_ex_display(xbt_ex_t * e)
134 char *thrower = NULL;
137 thrower = bprintf(" on host %s(%d)", e->host, e->pid);
140 "** SimGrid: UNCAUGHT EXCEPTION received on %s(%d): category: %s; value: %d\n"
142 "** Thrown by %s()%s\n",
143 gras_os_myname(), (*xbt_getpid) (),
144 xbt_ex_catname(e->category), e->value, e->msg,
145 e->procname, thrower ? thrower : " in this process");
146 CRITICAL1("%s", e->msg);
148 if (!e->remote && !e->bt_strings)
149 xbt_ex_setup_backtrace(e);
151 #ifdef HAVE_BACKTRACE
152 /* We have everything to build neat backtraces */
156 fprintf(stderr, "\n");
157 for (i = 0; i < e->used; i++)
158 fprintf(stderr, "%s\n", e->bt_strings[i]);
162 fprintf(stderr, " at %s:%d:%s (no backtrace available on that arch)\n",
163 e->file, e->line, e->func);
168 /* default __ex_terminate callback function */
169 void __xbt_ex_terminate_default(xbt_ex_t * e)
176 /* the externally visible API */
177 XBT_EXPORT_NO_IMPORT(ex_ctx_cb_t) __xbt_ex_ctx = &__xbt_ex_ctx_default;
178 XBT_EXPORT_NO_IMPORT(ex_term_cb_t) __xbt_ex_terminate =
179 &__xbt_ex_terminate_default;
182 void xbt_ex_free(xbt_ex_t e)
196 for (i = 0; i < e.used; i++)
197 free((char *) e.bt_strings[i]);
198 free((char **) e.bt_strings);
200 /* memset(e,0,sizeof(xbt_ex_t)); */
203 /** \brief returns a short name for the given exception category */
204 const char *xbt_ex_catname(xbt_errcat_t cat)
208 return "unknown_err";
210 return "invalid_arg";
213 case not_found_error:
218 return "network_err";
224 return "INVALID_ERR";
233 XBT_TEST_SUITE("xbt_ex", "Exception Handling");
235 XBT_TEST_UNIT("controlflow", test_controlflow, "basic nested control flow")
240 xbt_test_add0("basic nested control flow");
244 xbt_test_fail1("M1: n=%d (!= 1)", n);
248 xbt_test_fail1("M2: n=%d (!= 2)", n);
250 THROW0(unknown_error, 0, "something");
254 xbt_test_fail1("M3: n=%d (!= 3)", n);
261 xbt_test_fail1("M2: n=%d (!= 5)", n);
263 THROW0(unknown_error, 0, "something");
267 xbt_test_fail1("M3: n=%d (!= 6)", n);
272 xbt_test_fail1("MX: n=%d (shouldn't reach this point)", n);
276 xbt_test_fail1("M4: n=%d (!= 7)", n);
281 xbt_test_fail1("M5: n=%d (!= 8)", n);
284 XBT_TEST_UNIT("value", test_value, "exception value passing")
289 THROW0(unknown_error, 2, "toto");
292 xbt_test_add0("exception value passing");
293 if (ex.category != unknown_error)
294 xbt_test_fail1("category=%d (!= 1)", ex.category);
296 xbt_test_fail1("value=%d (!= 2)", ex.value);
297 if (strcmp(ex.msg, "toto"))
298 xbt_test_fail1("message=%s (!= toto)", ex.msg);
303 XBT_TEST_UNIT("variables", test_variables, "variable value preservation")
309 r1 = r2 = v1 = v2 = 1234;
313 THROW0(unknown_error, 0, "toto");
315 xbt_test_add0("variable preservation");
317 xbt_test_fail1("r1=%d (!= 1234)", r1);
319 xbt_test_fail1("v1=%d (!= 1234)", v1);
320 /* r2 is allowed to be destroyed because not volatile */
322 xbt_test_fail1("v2=%d (!= 5678)", v2);
327 XBT_TEST_UNIT("cleanup", test_cleanup, "cleanup handling")
333 xbt_test_add0("cleanup handling");
339 THROW0(1, 2, "blah");
342 xbt_test_fail1("v1 = %d (!= 5678)", v1);
347 xbt_test_fail1("v1 = %d (!= 5678)", v1);
348 if (!(ex.category == 1 && ex.value == 2 && !strcmp(ex.msg, "blah")))
349 xbt_test_fail0("unexpected exception contents");
353 xbt_test_fail0("xbt_ex_free not executed");
358 * The following is the example included in the documentation. It's a good
359 * idea to check its syntax even if we don't try to run it.
360 * And actually, it allows to put comments in the code despite doxygen.
362 static char *mallocex(int size)
367 #define SMALLAMOUNT 10
368 #define TOOBIG 100000000
370 #if 0 /* this contains syntax errors, actually */
371 static void bad_example(void)
380 char *cp1, *cp2, *cp3;
382 cp1 = mallocex(SMALLAMOUNT);
383 globalcontext->first = cp1;
384 cp2 = mallocex(TOOBIG);
385 cp3 = mallocex(SMALLAMOUNT);
397 printf("cp3=%s", cp3);
400 /* end_of_bad_example */
407 static void good_example(void)
409 global_context_t *global_context = malloc(sizeof(global_context_t));
414 char *volatile /*03 */ cp1 = NULL /*02 */ ;
415 char *volatile /*03 */ cp2 = NULL /*02 */ ;
416 char *volatile /*03 */ cp3 = NULL /*02 */ ;
418 cp1 = mallocex(SMALLAMOUNT);
419 global_context->first = cp1;
420 cp1 = NULL /*05 give away */ ;
421 cp2 = mallocex(TOOBIG);
422 cp3 = mallocex(SMALLAMOUNT);
425 } TRY_CLEANUP { /*04 */
426 printf("cp3=%s", cp3 == NULL /*02 */ ? "" : cp3);
431 /*05 cp1 was given away */
434 /*05 global context untouched */
438 /* end_of_good_example */
440 #endif /* SIMGRID_TEST */