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) {
41 /* Don't scream: this is a default which is never used (so, yes,
42 there is one setjump container by running entity).
44 This default gets overriden in xbt/xbt_os_thread.c so that it works in
45 real life and in simulation when using threads to implement the simulation
46 processes (ie, with pthreads and on windows).
48 It also gets overriden in xbt/context.c when using ucontextes (as well as
49 in Java for now, but after the java overhaul, it will get cleaned out)
51 static ex_ctx_t ctx = XBT_CTX_INITIALIZER;
56 /* Change raw libc symbols to file names and line numbers */
57 void xbt_ex_setup_backtrace(xbt_ex_t *e);
59 void xbt_backtrace_display(xbt_ex_t *e) {
60 xbt_ex_setup_backtrace(e);
64 fprintf(stderr,"(backtrace not set)\n");
68 fprintf(stderr,"Backtrace (displayed in thread %p):\n",
69 (void*)xbt_thread_self());
70 for (i=1; i<e->used; i++) /* no need to display "xbt_display_backtrace" */
71 fprintf(stderr,"---> %s\n",e->bt_strings[i] +4);
74 /* don't fool xbt_ex_free with uninitialized msg field */
80 ERROR0("No backtrace on this arch");
84 /** \brief show the backtrace of the current point (lovely while debuging) */
85 void xbt_backtrace_display_current(void) {
87 xbt_backtrace_current(&e);
88 xbt_backtrace_display(&e);
91 #if defined(HAVE_EXECINFO_H) && defined(HAVE_POPEN) && defined(ADDR2LINE)
92 # include "backtrace_linux.c"
93 #elif (defined(WIN32) && defined (_M_IX86)) && !defined(__GNUC__)
94 # include "backtrace_windows.c"
96 # include "backtrace_dummy.c"
99 /** @brief shows an exception content and the associated stack if available */
100 void xbt_ex_display(xbt_ex_t *e) {
104 thrower = bprintf(" on host %s(%d)",e->host,e->pid);
107 "** SimGrid: UNCAUGHT EXCEPTION received on %s(%d): category: %s; value: %d\n"
109 "** Thrown by %s()%s\n",
110 gras_os_myname(),(*xbt_getpid)(),
111 xbt_ex_catname(e->category), e->value, e->msg,
112 e->procname,thrower?thrower:" in this process");
113 CRITICAL1("%s",e->msg);
115 if (!e->remote && !e->bt_strings)
116 xbt_ex_setup_backtrace(e);
118 #ifdef HAVE_BACKTRACE
119 /* We have everything to build neat backtraces */
123 fprintf(stderr,"\n");
124 for (i=0; i<e->used; i++)
125 fprintf(stderr,"%s\n",e->bt_strings[i]);
129 fprintf(stderr," at %s:%d:%s (no backtrace available on that arch)\n",
130 e->file,e->line,e->func);
135 /* default __ex_terminate callback function */
136 void __xbt_ex_terminate_default(xbt_ex_t *e) {
142 /* the externally visible API */
143 XBT_EXPORT_NO_IMPORT(ex_ctx_cb_t) __xbt_ex_ctx = &__xbt_ex_ctx_default;
144 XBT_EXPORT_NO_IMPORT(ex_term_cb_t) __xbt_ex_terminate = &__xbt_ex_terminate_default;
147 void xbt_ex_free(xbt_ex_t e) {
150 if (e.msg) free(e.msg);
159 for (i=0; i<e.used; i++)
160 free((char*)e.bt_strings[i]);
161 free((char **)e.bt_strings);
163 /* memset(e,0,sizeof(xbt_ex_t)); */
166 /** \brief returns a short name for the given exception category */
167 const char * xbt_ex_catname(xbt_errcat_t cat) {
169 case unknown_error: return "unknown_err";
170 case arg_error: return "invalid_arg";
171 case mismatch_error: return "mismatch";
172 case not_found_error: return "not found";
173 case system_error: return "system_err";
174 case network_error: return "network_err";
175 case timeout_error: return "timeout";
176 case thread_error: return "thread_err";
177 default: return "INVALID_ERR";
186 XBT_TEST_SUITE("xbt_ex","Exception Handling");
188 XBT_TEST_UNIT("controlflow",test_controlflow, "basic nested control flow") {
192 xbt_test_add0("basic nested control flow");
196 xbt_test_fail1("M1: n=%d (!= 1)", n);
200 xbt_test_fail1("M2: n=%d (!= 2)", n);
202 THROW0(unknown_error,0,"something");
205 xbt_test_fail1("M3: n=%d (!= 3)", n);
212 xbt_test_fail1("M2: n=%d (!= 5)", n);
214 THROW0(unknown_error,0,"something");
217 xbt_test_fail1("M3: n=%d (!= 6)", n);
222 xbt_test_fail1("MX: n=%d (shouldn't reach this point)", n);
226 xbt_test_fail1("M4: n=%d (!= 7)", n);
231 xbt_test_fail1("M5: n=%d (!= 8)", n);
234 XBT_TEST_UNIT("value",test_value,"exception value passing") {
238 THROW0(unknown_error, 2, "toto");
240 xbt_test_add0("exception value passing");
241 if (ex.category != unknown_error)
242 xbt_test_fail1("category=%d (!= 1)", ex.category);
244 xbt_test_fail1("value=%d (!= 2)", ex.value);
245 if (strcmp(ex.msg,"toto"))
246 xbt_test_fail1("message=%s (!= toto)", ex.msg);
251 XBT_TEST_UNIT("variables",test_variables,"variable value preservation") {
256 r1 = r2 = v1 = v2 = 1234;
260 THROW0(unknown_error, 0, "toto");
262 xbt_test_add0("variable preservation");
264 xbt_test_fail1("r1=%d (!= 1234)", r1);
266 xbt_test_fail1("v1=%d (!= 1234)", v1);
267 /* r2 is allowed to be destroyed because not volatile */
269 xbt_test_fail1("v2=%d (!= 5678)", v2);
274 XBT_TEST_UNIT("cleanup",test_cleanup,"cleanup handling") {
279 xbt_test_add0("cleanup handling");
285 THROW0(1, 2, "blah");
288 xbt_test_fail1("v1 = %d (!= 5678)", v1);
292 xbt_test_fail1("v1 = %d (!= 5678)", v1);
293 if (!(ex.category == 1 && ex.value == 2 && !strcmp(ex.msg,"blah")))
294 xbt_test_fail0("unexpected exception contents");
298 xbt_test_fail0("xbt_ex_free not executed");
303 * The following is the example included in the documentation. It's a good
304 * idea to check its syntax even if we don't try to run it.
305 * And actually, it allows to put comments in the code despite doxygen.
307 static char *mallocex(int size) {
310 #define SMALLAMOUNT 10
311 #define TOOBIG 100000000
313 #if 0 /* this contains syntax errors, actually */
314 static void bad_example(void) {
315 struct {char*first;} *globalcontext;
320 char *cp1, *cp2, *cp3;
322 cp1 = mallocex(SMALLAMOUNT);
323 globalcontext->first = cp1;
324 cp2 = mallocex(TOOBIG);
325 cp3 = mallocex(SMALLAMOUNT);
329 if (cp3 != NULL) free(cp3);
330 if (cp2 != NULL) free(cp2);
331 if (cp1 != NULL) free(cp1);
333 printf("cp3=%s", cp3);
336 /* end_of_bad_example */
339 typedef struct {char *first;} global_context_t;
341 static void good_example(void) {
342 global_context_t *global_context=malloc(sizeof(global_context_t));
347 char * volatile /*03*/ cp1 = NULL /*02*/;
348 char * volatile /*03*/ cp2 = NULL /*02*/;
349 char * volatile /*03*/ cp3 = NULL /*02*/;
351 cp1 = mallocex(SMALLAMOUNT);
352 global_context->first = cp1;
353 cp1 = NULL /*05 give away*/;
354 cp2 = mallocex(TOOBIG);
355 cp3 = mallocex(SMALLAMOUNT);
359 printf("cp3=%s", cp3 == NULL /*02*/ ? "" : cp3);
364 /*05 cp1 was given away */
366 /*05 global context untouched */
370 /* end_of_good_example */
372 #endif /* SIMGRID_TEST */