3 /* ex - Exception Handling (modified to fit into SimGrid from OSSP version) */
5 /* Copyright (c) 2005, 2006, 2007 Martin Quinson */
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 program is free software; you can redistribute it and/or modify it
12 * under the terms of the license (GNU LGPL) which comes with this package. */
17 #include "portable.h" /* execinfo when available */
20 #include "xbt/module.h" /* xbt_binary_name */
21 #include "xbt_modinter.h" /* backtrace initialization headers */
22 #include "xbt/synchro.h" /* xbt_thread_self */
24 #include "gras/Virtu/virtu_interface.h" /* gras_os_myname */
25 #include "xbt/ex_interface.h"
28 #if defined(HAVE_EXECINFO_H) && defined(HAVE_POPEN) && defined(ADDR2LINE)
29 # define HAVE_BACKTRACE 1 /* Hello linux box */
32 #if defined(WIN32) && defined(_M_IX86) && !defined(__GNUC__)
33 # define HAVE_BACKTRACE 1 /* Hello x86 windows box */
37 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(xbt_ex, xbt, "Exception mecanism");
39 /* default __ex_ctx callback function */
40 ex_ctx_t *__xbt_ex_ctx_default(void)
42 /* Don't scream: this is a default which is never used (so, yes,
43 there is one setjump container by running entity).
45 This default gets overriden in xbt/xbt_os_thread.c so that it works in
46 real life and in simulation when using threads to implement the simulation
47 processes (ie, with pthreads and on windows).
49 It also gets overriden in xbt/context.c when using ucontextes (as well as
50 in Java for now, but after the java overhaul, it will get cleaned out)
52 static ex_ctx_t ctx = XBT_CTX_INITIALIZER;
57 /* Change raw libc symbols to file names and line numbers */
58 void xbt_ex_setup_backtrace(xbt_ex_t * e);
60 void xbt_backtrace_display(xbt_ex_t * e)
62 xbt_ex_setup_backtrace(e);
66 fprintf(stderr, "(backtrace not set)\n");
70 fprintf(stderr, "Backtrace (displayed in thread %p):\n",
71 (void *) xbt_thread_self());
72 for (i = 1; i < e->used; i++) /* no need to display "xbt_display_backtrace" */
73 fprintf(stderr, "---> %s\n", e->bt_strings[i] + 4);
76 /* don't fool xbt_ex_free with uninitialized msg field */
82 ERROR0("No backtrace on this arch");
86 /** \brief show the backtrace of the current point (lovely while debuging) */
87 void xbt_backtrace_display_current(void)
90 xbt_backtrace_current(&e);
91 xbt_backtrace_display(&e);
94 #if defined(HAVE_EXECINFO_H) && defined(HAVE_POPEN) && defined(ADDR2LINE)
95 # include "backtrace_linux.c"
96 #elif (defined(WIN32) && defined (_M_IX86)) && !defined(__GNUC__)
97 # include "backtrace_windows.c"
99 # include "backtrace_dummy.c"
102 /** @brief shows an exception content and the associated stack if available */
103 void xbt_ex_display(xbt_ex_t * e)
105 char *thrower = NULL;
108 thrower = bprintf(" on host %s(%d)", e->host, e->pid);
111 "** SimGrid: UNCAUGHT EXCEPTION received on %s(%d): category: %s; value: %d\n"
113 "** Thrown by %s()%s\n",
114 gras_os_myname(), (*xbt_getpid) (),
115 xbt_ex_catname(e->category), e->value, e->msg,
116 e->procname, thrower ? thrower : " in this process");
117 CRITICAL1("%s", e->msg);
119 if (!e->remote && !e->bt_strings)
120 xbt_ex_setup_backtrace(e);
122 #ifdef HAVE_BACKTRACE
123 /* We have everything to build neat backtraces */
127 fprintf(stderr, "\n");
128 for (i = 0; i < e->used; i++)
129 fprintf(stderr, "%s\n", e->bt_strings[i]);
133 fprintf(stderr, " at %s:%d:%s (no backtrace available on that arch)\n",
134 e->file, e->line, e->func);
139 /* default __ex_terminate callback function */
140 void __xbt_ex_terminate_default(xbt_ex_t * e)
147 /* the externally visible API */
148 XBT_EXPORT_NO_IMPORT(ex_ctx_cb_t) __xbt_ex_ctx = &__xbt_ex_ctx_default;
149 XBT_EXPORT_NO_IMPORT(ex_term_cb_t) __xbt_ex_terminate =
150 &__xbt_ex_terminate_default;
153 void xbt_ex_free(xbt_ex_t e)
167 for (i = 0; i < e.used; i++)
168 free((char *) e.bt_strings[i]);
169 free((char **) e.bt_strings);
171 /* memset(e,0,sizeof(xbt_ex_t)); */
174 /** \brief returns a short name for the given exception category */
175 const char *xbt_ex_catname(xbt_errcat_t cat)
179 return "unknown_err";
181 return "invalid_arg";
184 case not_found_error:
189 return "network_err";
195 return "INVALID_ERR";
204 XBT_TEST_SUITE("xbt_ex", "Exception Handling");
206 XBT_TEST_UNIT("controlflow", test_controlflow, "basic nested control flow")
211 xbt_test_add0("basic nested control flow");
215 xbt_test_fail1("M1: n=%d (!= 1)", n);
219 xbt_test_fail1("M2: n=%d (!= 2)", n);
221 THROW0(unknown_error, 0, "something");
225 xbt_test_fail1("M3: n=%d (!= 3)", n);
232 xbt_test_fail1("M2: n=%d (!= 5)", n);
234 THROW0(unknown_error, 0, "something");
238 xbt_test_fail1("M3: n=%d (!= 6)", n);
243 xbt_test_fail1("MX: n=%d (shouldn't reach this point)", n);
247 xbt_test_fail1("M4: n=%d (!= 7)", n);
252 xbt_test_fail1("M5: n=%d (!= 8)", n);
255 XBT_TEST_UNIT("value", test_value, "exception value passing")
260 THROW0(unknown_error, 2, "toto");
263 xbt_test_add0("exception value passing");
264 if (ex.category != unknown_error)
265 xbt_test_fail1("category=%d (!= 1)", ex.category);
267 xbt_test_fail1("value=%d (!= 2)", ex.value);
268 if (strcmp(ex.msg, "toto"))
269 xbt_test_fail1("message=%s (!= toto)", ex.msg);
274 XBT_TEST_UNIT("variables", test_variables, "variable value preservation")
280 r1 = r2 = v1 = v2 = 1234;
284 THROW0(unknown_error, 0, "toto");
286 xbt_test_add0("variable preservation");
288 xbt_test_fail1("r1=%d (!= 1234)", r1);
290 xbt_test_fail1("v1=%d (!= 1234)", v1);
291 /* r2 is allowed to be destroyed because not volatile */
293 xbt_test_fail1("v2=%d (!= 5678)", v2);
298 XBT_TEST_UNIT("cleanup", test_cleanup, "cleanup handling")
304 xbt_test_add0("cleanup handling");
310 THROW0(1, 2, "blah");
313 xbt_test_fail1("v1 = %d (!= 5678)", v1);
318 xbt_test_fail1("v1 = %d (!= 5678)", v1);
319 if (!(ex.category == 1 && ex.value == 2 && !strcmp(ex.msg, "blah")))
320 xbt_test_fail0("unexpected exception contents");
324 xbt_test_fail0("xbt_ex_free not executed");
329 * The following is the example included in the documentation. It's a good
330 * idea to check its syntax even if we don't try to run it.
331 * And actually, it allows to put comments in the code despite doxygen.
333 static char *mallocex(int size)
338 #define SMALLAMOUNT 10
339 #define TOOBIG 100000000
341 #if 0 /* this contains syntax errors, actually */
342 static void bad_example(void)
351 char *cp1, *cp2, *cp3;
353 cp1 = mallocex(SMALLAMOUNT);
354 globalcontext->first = cp1;
355 cp2 = mallocex(TOOBIG);
356 cp3 = mallocex(SMALLAMOUNT);
368 printf("cp3=%s", cp3);
371 /* end_of_bad_example */
378 static void good_example(void)
380 global_context_t *global_context = malloc(sizeof(global_context_t));
385 char *volatile /*03 */ cp1 = NULL /*02 */ ;
386 char *volatile /*03 */ cp2 = NULL /*02 */ ;
387 char *volatile /*03 */ cp3 = NULL /*02 */ ;
389 cp1 = mallocex(SMALLAMOUNT);
390 global_context->first = cp1;
391 cp1 = NULL /*05 give away */ ;
392 cp2 = mallocex(TOOBIG);
393 cp3 = mallocex(SMALLAMOUNT);
397 printf("cp3=%s", cp3 == NULL /*02 */ ? "" : cp3);
402 /*05 cp1 was given away */
405 /*05 global context untouched */
409 /* end_of_good_example */
411 #endif /* SIMGRID_TEST */