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 XBT_EXPORT_NO_IMPORT(const xbt_running_ctx_t) __xbt_ex_ctx_initializer = XBT_RUNNING_CTX_INITIALIZER;
70 /* default __ex_ctx callback function */
71 xbt_running_ctx_t *__xbt_ex_ctx_default(void)
73 /* Don't scream: this is a default which is never used (so, yes,
74 there is one setjump container by running entity).
76 This default gets overriden in xbt/xbt_os_thread.c so that it works in
77 real life and in simulation when using threads to implement the simulation
78 processes (ie, with pthreads and on windows).
80 It also gets overriden in xbt/context.c when using ucontextes (as well as
81 in Java for now, but after the java overhaul, it will get cleaned out)
83 static xbt_running_ctx_t ctx = XBT_RUNNING_CTX_INITIALIZER;
88 /* Change raw libc symbols to file names and line numbers */
89 void xbt_ex_setup_backtrace(xbt_ex_t * e);
91 void xbt_backtrace_display(xbt_ex_t * e)
93 xbt_ex_setup_backtrace(e);
97 fprintf(stderr, "(backtrace not set)\n");
101 fprintf(stderr, "Backtrace (displayed in thread %p):\n",
102 (void *) xbt_thread_self());
103 for (i = 1; i < e->used; i++) /* no need to display "xbt_backtrace_display" */
104 fprintf(stderr, "---> %s\n", e->bt_strings[i] + 4);
107 /* don't fool xbt_ex_free with uninitialized msg field */
113 XBT_ERROR("No backtrace on this arch");
117 /** \brief show the backtrace of the current point (lovely while debuging) */
118 void xbt_backtrace_display_current(void)
121 xbt_backtrace_current(&e);
122 xbt_backtrace_display(&e);
125 #if defined(HAVE_EXECINFO_H) && defined(HAVE_POPEN) && defined(ADDR2LINE)
126 # include "backtrace_linux.c"
127 #elif (defined(_XBT_WIN32) && defined (_M_IX86)) && !defined(__GNUC__)
128 # include "backtrace_windows.c"
130 # include "backtrace_dummy.c"
133 /** @brief shows an exception content and the associated stack if available */
134 void xbt_ex_display(xbt_ex_t * e)
136 char *thrower = NULL;
139 thrower = bprintf(" on host %s(%d)", e->host, e->pid);
142 "** SimGrid: UNCAUGHT EXCEPTION received on %s(%d): category: %s; value: %d\n"
144 "** Thrown by %s()%s\n",
145 gras_os_myname(), xbt_getpid(),
146 xbt_ex_catname(e->category), e->value, e->msg,
147 e->procname, thrower ? thrower : " in this process");
148 XBT_CRITICAL("%s", e->msg);
150 if (!e->remote && !e->bt_strings)
151 xbt_ex_setup_backtrace(e);
153 #ifdef HAVE_BACKTRACE
154 /* We have everything to build neat backtraces */
158 if (!xbt_binary_name) {
159 fprintf(stderr, "variable 'xbt_binary_name' set to NULL. Cannot compute the backtrace\n");
162 fprintf(stderr, "\n");
163 for (i = 0; i < e->used; i++)
164 fprintf(stderr, "%s\n", e->bt_strings[i]);
168 fprintf(stderr, " at %s:%d:%s (no backtrace available on that arch)\n",
169 e->file, e->line, e->func);
174 /* default __ex_terminate callback function */
175 void __xbt_ex_terminate_default(xbt_ex_t * e)
182 /* the externally visible API */
183 XBT_EXPORT_NO_IMPORT(xbt_running_ctx_fetcher_t) __xbt_running_ctx_fetch = &__xbt_ex_ctx_default;
184 XBT_EXPORT_NO_IMPORT(ex_term_cb_t) __xbt_ex_terminate =
185 &__xbt_ex_terminate_default;
188 void xbt_ex_free(xbt_ex_t e)
201 for (i = 0; i < e.used; i++)
202 free(e.bt_strings[i]);
205 /* memset(e,0,sizeof(xbt_ex_t)); */
208 /** \brief returns a short name for the given exception category */
209 const char *xbt_ex_catname(xbt_errcat_t cat)
213 return "unknown_err";
215 return "invalid_arg";
218 case not_found_error:
223 return "network_err";
229 return "INVALID_ERR";
238 XBT_TEST_SUITE("xbt_ex", "Exception Handling");
240 XBT_TEST_UNIT("controlflow", test_controlflow, "basic nested control flow")
245 xbt_test_add("basic nested control flow");
249 xbt_test_fail("M1: n=%d (!= 1)", n);
253 xbt_test_fail("M2: n=%d (!= 2)", n);
255 THROWF(unknown_error, 0, "something");
259 xbt_test_fail("M3: n=%d (!= 3)", n);
266 xbt_test_fail("M2: n=%d (!= 5)", n);
268 THROWF(unknown_error, 0, "something");
272 xbt_test_fail("M3: n=%d (!= 6)", n);
277 xbt_test_fail("MX: n=%d (shouldn't reach this point)", n);
281 xbt_test_fail("M4: n=%d (!= 7)", n);
286 xbt_test_fail("M5: n=%d (!= 8)", n);
289 XBT_TEST_UNIT("value", test_value, "exception value passing")
294 THROWF(unknown_error, 2, "toto");
297 xbt_test_add("exception value passing");
298 if (ex.category != unknown_error)
299 xbt_test_fail("category=%d (!= 1)", ex.category);
301 xbt_test_fail("value=%d (!= 2)", ex.value);
302 if (strcmp(ex.msg, "toto"))
303 xbt_test_fail("message=%s (!= toto)", ex.msg);
308 XBT_TEST_UNIT("variables", test_variables, "variable value preservation")
314 r1 = r2 = v1 = v2 = 1234;
318 THROWF(unknown_error, 0, "toto");
321 xbt_test_add("variable preservation");
323 xbt_test_fail("r1=%d (!= 1234)", r1);
325 xbt_test_fail("v1=%d (!= 1234)", v1);
326 /* r2 is allowed to be destroyed because not volatile */
328 xbt_test_fail("v2=%d (!= 5678)", v2);
333 XBT_TEST_UNIT("cleanup", test_cleanup, "cleanup handling")
339 xbt_test_add("cleanup handling");
345 THROWF(1, 2, "blah");
349 xbt_test_fail("v1 = %d (!= 5678)", v1);
354 xbt_test_fail("v1 = %d (!= 5678)", v1);
355 if (!(ex.category == 1 && ex.value == 2 && !strcmp(ex.msg, "blah")))
356 xbt_test_fail("unexpected exception contents");
360 xbt_test_fail("xbt_ex_free not executed");
365 * The following is the example included in the documentation. It's a good
366 * idea to check its syntax even if we don't try to run it.
367 * And actually, it allows to put comments in the code despite doxygen.
369 static char *mallocex(int size)
374 #define SMALLAMOUNT 10
375 #define TOOBIG 100000000
377 #if 0 /* this contains syntax errors, actually */
378 static void bad_example(void)
387 char *cp1, *cp2, *cp3;
389 cp1 = mallocex(SMALLAMOUNT);
390 globalcontext->first = cp1;
391 cp2 = mallocex(TOOBIG);
392 cp3 = mallocex(SMALLAMOUNT);
402 printf("cp3=%s", cp3);
405 /* end_of_bad_example */
412 static void good_example(void)
414 global_context_t *global_context = malloc(sizeof(global_context_t));
418 char *volatile /*03 */ cp1 = NULL /*02 */ ;
419 char *volatile /*03 */ cp2 = NULL /*02 */ ;
420 char *volatile /*03 */ cp3 = NULL /*02 */ ;
422 cp1 = mallocex(SMALLAMOUNT);
423 global_context->first = cp1;
424 cp1 = NULL /*05 give away */ ;
425 cp2 = mallocex(TOOBIG);
426 cp3 = mallocex(SMALLAMOUNT);
430 TRY_CLEANUP { /*04 */
431 printf("cp3=%s", cp3 == NULL /*02 */ ? "" : cp3);
434 /*05 cp1 was given away */
437 /*05 global context untouched */
441 /* end_of_good_example */
443 #endif /* SIMGRID_TEST */