1 /* ex - Exception Handling */
3 /* Copyright (c) 2005-2014. The SimGrid Team.
4 * All rights reserved. */
6 /* Copyright (c) 2002-2004 Ralf S. Engelschall <rse@engelschall.com> */
7 /* Copyright (c) 2002-2004 The OSSP Project <http://www.ossp.org/> */
8 /* Copyright (c) 2002-2004 Cable & Wireless <http://www.cw.com/> */
9 /* All rights reserved. */
11 /* This code is inspirated from the OSSP version (as retrieved back in 2004)*/
12 /* It was heavily modified to fit the SimGrid framework. */
14 /* The OSSP version has the following copyright notice:
15 ** OSSP ex - Exception Handling
16 ** Copyright (c) 2002-2004 Ralf S. Engelschall <rse@engelschall.com>
17 ** Copyright (c) 2002-2004 The OSSP Project <http://www.ossp.org/>
18 ** Copyright (c) 2002-2004 Cable & Wireless <http://www.cw.com/>
20 ** This file is part of OSSP ex, an exception handling library
21 ** which can be found at http://www.ossp.org/pkg/lib/ex/.
23 ** Permission to use, copy, modify, and distribute this software for
24 ** any purpose with or without fee is hereby granted, provided that
25 ** the above copyright notice and this permission notice appear in all
28 ** THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESSED OR IMPLIED
29 ** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
30 ** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
31 ** IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
32 ** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
35 ** USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
36 ** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
37 ** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
38 ** OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42 /* The extensions made for the SimGrid project can either be distributed */
43 /* under the same license, or under the LGPL v2.1 */
48 #include "portable.h" /* execinfo when available */
51 #include "xbt/synchro_core.h"
52 #include "xbt_modinter.h" /* backtrace initialization headers */
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 ucontexts (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 */
112 XBT_ERROR("No backtrace on this arch");
116 /** \brief show the backtrace of the current point (lovely while debuging) */
117 void xbt_backtrace_display_current(void)
120 xbt_backtrace_current(&e);
121 xbt_backtrace_display(&e);
124 #if defined(HAVE_EXECINFO_H) && defined(HAVE_POPEN) && defined(ADDR2LINE)
125 # include "backtrace_linux.c"
126 #elif (defined(_XBT_WIN32) && defined (_M_IX86)) && !defined(__GNUC__)
127 # include "backtrace_windows.c"
129 # include "backtrace_dummy.c"
132 /** @brief shows an exception content and the associated stack if available */
133 void xbt_ex_display(xbt_ex_t * e)
135 char *thrower = NULL;
136 if (e->pid != xbt_getpid())
137 thrower = bprintf(" on process %d",e->pid);
140 "** SimGrid: UNCAUGHT EXCEPTION received on %s(%d): category: %s; value: %d\n"
142 "** Thrown by %s()%s\n",
143 xbt_binary_name, xbt_getpid(),
144 xbt_ex_catname(e->category), e->value, e->msg,
145 e->procname, thrower ? thrower : " in this process");
146 XBT_CRITICAL("%s", e->msg);
150 xbt_ex_setup_backtrace(e);
152 #ifdef HAVE_BACKTRACE
153 if (e->used && e->bt_strings) {
154 /* We have everything to build neat backtraces */
157 fprintf(stderr, "\n");
158 for (i = 0; i < e->used; i++)
159 fprintf(stderr, "%s\n", e->bt_strings[i]);
166 "** In %s() at %s:%d\n"
167 "** (no backtrace available)\n",
168 e->func, e->file, e->line);
173 /* default __ex_terminate callback function */
174 void __xbt_ex_terminate_default(xbt_ex_t * e)
180 /* the externally visible API */
181 XBT_EXPORT_NO_IMPORT(xbt_running_ctx_fetcher_t) __xbt_running_ctx_fetch = &__xbt_ex_ctx_default;
182 XBT_EXPORT_NO_IMPORT(ex_term_cb_t) __xbt_ex_terminate = &__xbt_ex_terminate_default;
185 void xbt_ex_free(xbt_ex_t e)
192 for (i = 0; i < e.used; i++)
193 free(e.bt_strings[i]);
196 /* memset(e,0,sizeof(xbt_ex_t)); */
199 /** \brief returns a short name for the given exception category */
200 const char *xbt_ex_catname(xbt_errcat_t cat)
204 return "unknown error";
206 return "invalid argument";
208 return "out of bounds";
211 case not_found_error:
214 return "system error";
216 return "network error";
220 return "action canceled";
222 return "thread error";
224 return "host failed";
226 return "tracing error";
233 return "INVALID ERROR";
241 XBT_TEST_SUITE("xbt_ex", "Exception Handling");
243 XBT_TEST_UNIT("controlflow", test_controlflow, "basic nested control flow")
248 xbt_test_add("basic nested control flow");
252 xbt_test_fail("M1: n=%d (!= 1)", n);
256 xbt_test_fail("M2: n=%d (!= 2)", n);
258 THROWF(unknown_error, 0, "something");
262 xbt_test_fail("M3: n=%d (!= 3)", n);
269 xbt_test_fail("M2: n=%d (!= 5)", n);
271 THROWF(unknown_error, 0, "something");
275 xbt_test_fail("M3: n=%d (!= 6)", n);
280 xbt_test_fail("MX: n=%d (shouldn't reach this point)", n);
284 xbt_test_fail("M4: n=%d (!= 7)", n);
289 xbt_test_fail("M5: n=%d (!= 8)", n);
292 XBT_TEST_UNIT("value", test_value, "exception value passing")
297 THROWF(unknown_error, 2, "toto");
300 xbt_test_add("exception value passing");
301 if (ex.category != unknown_error)
302 xbt_test_fail("category=%d (!= 1)", (int)ex.category);
304 xbt_test_fail("value=%d (!= 2)", ex.value);
305 if (strcmp(ex.msg, "toto"))
306 xbt_test_fail("message=%s (!= toto)", ex.msg);
311 XBT_TEST_UNIT("variables", test_variables, "variable value preservation")
315 int _XBT_GNUC_UNUSED r2;
319 r1 = r2 = v1 = v2 = 1234;
323 THROWF(unknown_error, 0, "toto");
326 xbt_test_add("variable preservation");
328 xbt_test_fail("r1=%d (!= 1234)", r1);
330 xbt_test_fail("v1=%d (!= 1234)", v1);
331 /* r2 is allowed to be destroyed because not volatile */
333 xbt_test_fail("v2=%d (!= 5678)", v2);
338 XBT_TEST_UNIT("cleanup", test_cleanup, "cleanup handling")
344 xbt_test_add("cleanup handling");
350 THROWF(1, 2, "blah");
354 xbt_test_fail("v1 = %d (!= 5678)", v1);
359 xbt_test_fail("v1 = %d (!= 5678)", v1);
360 if (!(ex.category == 1 && ex.value == 2 && !strcmp(ex.msg, "blah")))
361 xbt_test_fail("unexpected exception contents");
365 xbt_test_fail("xbt_ex_free not executed");
370 * The following is the example included in the documentation. It's a good
371 * idea to check its syntax even if we don't try to run it.
372 * And actually, it allows to put comments in the code despite doxygen.
374 static char *mallocex(int size)
379 #define SMALLAMOUNT 10
380 #define TOOBIG 100000000
382 #if 0 /* this contains syntax errors, actually */
383 static void bad_example(void)
392 char *cp1, *cp2, *cp3;
394 cp1 = mallocex(SMALLAMOUNT);
395 globalcontext->first = cp1;
396 cp2 = mallocex(TOOBIG);
397 cp3 = mallocex(SMALLAMOUNT);
407 printf("cp3=%s", cp3);
410 /* end_of_bad_example */
417 static void good_example(void)
419 global_context_t *global_context = xbt_malloc(sizeof(global_context_t));
423 char *volatile /*03 */ cp1 = NULL /*02 */ ;
424 char *volatile /*03 */ cp2 = NULL /*02 */ ;
425 char *volatile /*03 */ cp3 = NULL /*02 */ ;
427 cp1 = mallocex(SMALLAMOUNT);
428 global_context->first = cp1;
429 cp1 = NULL /*05 give away */ ;
430 cp2 = mallocex(TOOBIG);
431 cp3 = mallocex(SMALLAMOUNT);
435 TRY_CLEANUP { /*04 */
436 printf("cp3=%s", cp3 == NULL /*02 */ ? "" : cp3);
439 /*05 cp1 was given away */
442 /*05 global context untouched */
446 /* end_of_good_example */
448 #endif /* SIMGRID_TEST */