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_modinter.h" /* backtrace initialization headers */
51 #include "xbt/ex_interface.h"
54 #if defined(HAVE_EXECINFO_H) && defined(HAVE_POPEN) && defined(ADDR2LINE)
55 # define HAVE_BACKTRACE 1 /* Hello linux box */
58 #if defined(_XBT_WIN32) && defined(_M_IX86) && !defined(__GNUC__)
59 # define HAVE_BACKTRACE 1 /* Hello x86 windows box */
63 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(xbt_ex, xbt, "Exception mecanism");
65 XBT_EXPORT_NO_IMPORT(const xbt_running_ctx_t) __xbt_ex_ctx_initializer = XBT_RUNNING_CTX_INITIALIZER;
67 /* default __ex_ctx callback function */
68 xbt_running_ctx_t *__xbt_ex_ctx_default(void)
70 /* Don't scream: this is a default which is never used (so, yes,
71 there is one setjump container by running entity).
73 This default gets overriden in xbt/xbt_os_thread.c so that it works in
74 real life and in simulation when using threads to implement the simulation
75 processes (ie, with pthreads and on windows).
77 It also gets overriden in xbt/context.c when using ucontextes (as well as
78 in Java for now, but after the java overhaul, it will get cleaned out)
80 static xbt_running_ctx_t ctx = XBT_RUNNING_CTX_INITIALIZER;
85 /* Change raw libc symbols to file names and line numbers */
86 void xbt_ex_setup_backtrace(xbt_ex_t * e);
88 void xbt_backtrace_display(xbt_ex_t * e)
90 xbt_ex_setup_backtrace(e);
94 fprintf(stderr, "(backtrace not set)\n");
98 fprintf(stderr, "Backtrace (displayed in thread %p):\n",
99 (void *) xbt_thread_self());
100 for (i = 1; i < e->used; i++) /* no need to display "xbt_backtrace_display" */
101 fprintf(stderr, "---> %s\n", e->bt_strings[i] + 4);
104 /* don't fool xbt_ex_free with uninitialized msg field */
109 XBT_ERROR("No backtrace on this arch");
113 /** \brief show the backtrace of the current point (lovely while debuging) */
114 void xbt_backtrace_display_current(void)
117 xbt_backtrace_current(&e);
118 xbt_backtrace_display(&e);
121 #if defined(HAVE_EXECINFO_H) && defined(HAVE_POPEN) && defined(ADDR2LINE)
122 # include "backtrace_linux.c"
123 #elif (defined(_XBT_WIN32) && defined (_M_IX86)) && !defined(__GNUC__)
124 # include "backtrace_windows.c"
126 # include "backtrace_dummy.c"
129 /** @brief shows an exception content and the associated stack if available */
130 void xbt_ex_display(xbt_ex_t * e)
132 char *thrower = NULL;
135 "** SimGrid: UNCAUGHT EXCEPTION received on %s(%d): category: %s; value: %d\n"
137 "** Thrown by %s()%s\n",
138 xbt_binary_name, xbt_getpid(),
139 xbt_ex_catname(e->category), e->value, e->msg,
140 e->procname, thrower ? thrower : " in this process");
141 XBT_CRITICAL("%s", e->msg);
145 xbt_ex_setup_backtrace(e);
147 #ifdef HAVE_BACKTRACE
148 if (e->used && e->bt_strings) {
149 /* We have everything to build neat backtraces */
152 fprintf(stderr, "\n");
153 for (i = 0; i < e->used; i++)
154 fprintf(stderr, "%s\n", e->bt_strings[i]);
161 "** In %s() at %s:%d\n"
162 "** (no backtrace available)\n",
163 e->func, e->file, e->line);
168 /* default __ex_terminate callback function */
169 void __xbt_ex_terminate_default(xbt_ex_t * e)
175 /* the externally visible API */
176 XBT_EXPORT_NO_IMPORT(xbt_running_ctx_fetcher_t) __xbt_running_ctx_fetch = &__xbt_ex_ctx_default;
177 XBT_EXPORT_NO_IMPORT(ex_term_cb_t) __xbt_ex_terminate =
178 &__xbt_ex_terminate_default;
181 void xbt_ex_free(xbt_ex_t e)
188 for (i = 0; i < e.used; i++)
189 free(e.bt_strings[i]);
192 /* memset(e,0,sizeof(xbt_ex_t)); */
195 /** \brief returns a short name for the given exception category */
196 const char *xbt_ex_catname(xbt_errcat_t cat)
200 return "unknown error";
202 return "invalid argument";
204 return "out of bounds";
207 case not_found_error:
210 return "system error";
212 return "network error";
216 return "action canceled";
218 return "thread error";
220 return "host failed";
222 return "tracing error";
229 return "INVALID ERROR";
237 XBT_TEST_SUITE("xbt_ex", "Exception Handling");
239 XBT_TEST_UNIT("controlflow", test_controlflow, "basic nested control flow")
244 xbt_test_add("basic nested control flow");
248 xbt_test_fail("M1: n=%d (!= 1)", n);
252 xbt_test_fail("M2: n=%d (!= 2)", n);
254 THROWF(unknown_error, 0, "something");
258 xbt_test_fail("M3: n=%d (!= 3)", n);
265 xbt_test_fail("M2: n=%d (!= 5)", n);
267 THROWF(unknown_error, 0, "something");
271 xbt_test_fail("M3: n=%d (!= 6)", n);
276 xbt_test_fail("MX: n=%d (shouldn't reach this point)", n);
280 xbt_test_fail("M4: n=%d (!= 7)", n);
285 xbt_test_fail("M5: n=%d (!= 8)", n);
288 XBT_TEST_UNIT("value", test_value, "exception value passing")
293 THROWF(unknown_error, 2, "toto");
296 xbt_test_add("exception value passing");
297 if (ex.category != unknown_error)
298 xbt_test_fail("category=%d (!= 1)", (int)ex.category);
300 xbt_test_fail("value=%d (!= 2)", ex.value);
301 if (strcmp(ex.msg, "toto"))
302 xbt_test_fail("message=%s (!= toto)", ex.msg);
307 XBT_TEST_UNIT("variables", test_variables, "variable value preservation")
311 int _XBT_GNUC_UNUSED r2;
315 r1 = r2 = v1 = v2 = 1234;
319 THROWF(unknown_error, 0, "toto");
322 xbt_test_add("variable preservation");
324 xbt_test_fail("r1=%d (!= 1234)", r1);
326 xbt_test_fail("v1=%d (!= 1234)", v1);
327 /* r2 is allowed to be destroyed because not volatile */
329 xbt_test_fail("v2=%d (!= 5678)", v2);
334 XBT_TEST_UNIT("cleanup", test_cleanup, "cleanup handling")
340 xbt_test_add("cleanup handling");
346 THROWF(1, 2, "blah");
350 xbt_test_fail("v1 = %d (!= 5678)", v1);
355 xbt_test_fail("v1 = %d (!= 5678)", v1);
356 if (!(ex.category == 1 && ex.value == 2 && !strcmp(ex.msg, "blah")))
357 xbt_test_fail("unexpected exception contents");
361 xbt_test_fail("xbt_ex_free not executed");
366 * The following is the example included in the documentation. It's a good
367 * idea to check its syntax even if we don't try to run it.
368 * And actually, it allows to put comments in the code despite doxygen.
370 static char *mallocex(int size)
375 #define SMALLAMOUNT 10
376 #define TOOBIG 100000000
378 #if 0 /* this contains syntax errors, actually */
379 static void bad_example(void)
388 char *cp1, *cp2, *cp3;
390 cp1 = mallocex(SMALLAMOUNT);
391 globalcontext->first = cp1;
392 cp2 = mallocex(TOOBIG);
393 cp3 = mallocex(SMALLAMOUNT);
403 printf("cp3=%s", cp3);
406 /* end_of_bad_example */
413 static void good_example(void)
415 global_context_t *global_context = xbt_malloc(sizeof(global_context_t));
419 char *volatile /*03 */ cp1 = NULL /*02 */ ;
420 char *volatile /*03 */ cp2 = NULL /*02 */ ;
421 char *volatile /*03 */ cp3 = NULL /*02 */ ;
423 cp1 = mallocex(SMALLAMOUNT);
424 global_context->first = cp1;
425 cp1 = NULL /*05 give away */ ;
426 cp2 = mallocex(TOOBIG);
427 cp3 = mallocex(SMALLAMOUNT);
431 TRY_CLEANUP { /*04 */
432 printf("cp3=%s", cp3 == NULL /*02 */ ? "" : cp3);
435 /*05 cp1 was given away */
438 /*05 global context untouched */
442 /* end_of_good_example */
444 #endif /* SIMGRID_TEST */