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/synchro.h" /* xbt_thread_self */
23 #include "gras/Virtu/virtu_interface.h" /* gras_os_myname */
24 #include "xbt/ex_interface.h"
27 #if defined(HAVE_EXECINFO_H) && defined(HAVE_POPEN) && defined(ADDR2LINE)
28 # define HAVE_BACKTRACE 1 /* Hello linux box */
31 #if defined(WIN32) && defined(_M_IX86)
32 # define HAVE_BACKTRACE 1 /* Hello x86 windows box */
36 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(xbt_ex,xbt,"Exception mecanism");
38 /* default __ex_ctx callback function */
39 ex_ctx_t *__xbt_ex_ctx_default(void) {
40 /* Don't scream: this is a default which is never used (so, yes,
41 there is one setjump container by running entity).
43 This default gets overriden in xbt/xbt_os_thread.c so that it works in
44 real life and in simulation when using threads to implement the simulation
45 processes (ie, with pthreads and on windows).
47 It also gets overriden in xbt/context.c when using ucontextes (as well as
48 in Java for now, but after the java overhaul, it will get cleaned out)
50 static ex_ctx_t ctx = XBT_CTX_INITIALIZER;
55 /* Change raw libc symbols to file names and line numbers */
56 void xbt_ex_setup_backtrace(xbt_ex_t *e);
58 void xbt_backtrace_current(xbt_ex_t *e) {
60 e->used = backtrace((void**)e->bt,XBT_BACKTRACE_SIZE);
62 xbt_ex_setup_backtrace(e);
66 void xbt_backtrace_display(xbt_ex_t *e) {
71 fprintf(stderr,"(backtrace not set)\n");
73 fprintf(stderr,"Backtrace (displayed in thread %p):\n",
74 (void*)xbt_thread_self());
75 for (i=1; i<e->used; i++) /* no need to display "xbt_display_backtrace" */
76 fprintf(stderr,"---> %s\n",e->bt_strings[i] +4);
79 /* don't fool xbt_ex_free with uninitialized msg field */
85 ERROR0("No backtrace on this arch");
89 /** \brief show the backtrace of the current point (lovely while debuging) */
90 void xbt_backtrace_display_current(void) {
92 xbt_backtrace_current(&e);
93 xbt_backtrace_display(&e);
96 #if defined(HAVE_EXECINFO_H) && defined(HAVE_POPEN) && defined(ADDR2LINE)
97 # include "backtrace_linux.c"
98 #elif (defined(WIN32) && defined (_M_IX86))
99 # include "backtrace_windows.c"
101 void xbt_ex_setup_backtrace(xbt_ex_t *e) {
105 /** @brief shows an exception content and the associated stack if available */
106 void xbt_ex_display(xbt_ex_t *e) {
110 thrower = bprintf(" on host %s(%d)",e->host,e->pid);
113 "** SimGrid: UNCAUGHT EXCEPTION received on %s(%d): category: %s; value: %d\n"
115 "** Thrown by %s()%s\n",
116 gras_os_myname(),(*xbt_getpid)(),
117 xbt_ex_catname(e->category), e->value, e->msg,
118 e->procname,thrower?thrower:" in this process");
119 CRITICAL1("%s",e->msg);
124 if (!e->remote && !e->bt_strings)
125 xbt_ex_setup_backtrace(e);
127 #ifdef HAVE_BACKTRACE
128 /* We have everything to build neat backtraces */
132 fprintf(stderr,"\n");
133 for (i=0; i<e->used; i++)
134 fprintf(stderr,"%s\n",e->bt_strings[i]);
138 fprintf(stderr," at %s:%d:%s (no backtrace available on that arch)\n",
139 e->file,e->line,e->func);
145 /* default __ex_terminate callback function */
146 void __xbt_ex_terminate_default(xbt_ex_t *e) {
152 /* the externally visible API */
153 XBT_EXPORT_NO_IMPORT(ex_ctx_cb_t) __xbt_ex_ctx = &__xbt_ex_ctx_default;
154 XBT_EXPORT_NO_IMPORT(ex_term_cb_t) __xbt_ex_terminate = &__xbt_ex_terminate_default;
157 void xbt_ex_free(xbt_ex_t e) {
160 if (e.msg) free(e.msg);
169 for (i=0; i<e.used; i++)
170 free((char*)e.bt_strings[i]);
171 free((char **)e.bt_strings);
173 /* memset(e,0,sizeof(xbt_ex_t)); */
176 /** \brief returns a short name for the given exception category */
177 const char * xbt_ex_catname(xbt_errcat_t cat) {
179 case unknown_error: return "unknown_err";
180 case arg_error: return "invalid_arg";
181 case mismatch_error: return "mismatch";
182 case not_found_error: return "not found";
183 case system_error: return "system_err";
184 case network_error: return "network_err";
185 case timeout_error: return "timeout";
186 case thread_error: return "thread_err";
187 default: return "INVALID_ERR";
196 XBT_TEST_SUITE("xbt_ex","Exception Handling");
198 XBT_TEST_UNIT("controlflow",test_controlflow, "basic nested control flow") {
202 xbt_test_add0("basic nested control flow");
206 xbt_test_fail1("M1: n=%d (!= 1)", n);
210 xbt_test_fail1("M2: n=%d (!= 2)", n);
212 THROW0(unknown_error,0,"something");
215 xbt_test_fail1("M3: n=%d (!= 3)", n);
222 xbt_test_fail1("M2: n=%d (!= 5)", n);
224 THROW0(unknown_error,0,"something");
227 xbt_test_fail1("M3: n=%d (!= 6)", n);
232 xbt_test_fail1("MX: n=%d (shouldn't reach this point)", n);
236 xbt_test_fail1("M4: n=%d (!= 7)", n);
241 xbt_test_fail1("M5: n=%d (!= 8)", n);
244 XBT_TEST_UNIT("value",test_value,"exception value passing") {
248 THROW0(unknown_error, 2, "toto");
250 xbt_test_add0("exception value passing");
251 if (ex.category != unknown_error)
252 xbt_test_fail1("category=%d (!= 1)", ex.category);
254 xbt_test_fail1("value=%d (!= 2)", ex.value);
255 if (strcmp(ex.msg,"toto"))
256 xbt_test_fail1("message=%s (!= toto)", ex.msg);
261 XBT_TEST_UNIT("variables",test_variables,"variable value preservation") {
266 r1 = r2 = v1 = v2 = 1234;
270 THROW0(unknown_error, 0, "toto");
272 xbt_test_add0("variable preservation");
274 xbt_test_fail1("r1=%d (!= 1234)", r1);
276 xbt_test_fail1("v1=%d (!= 1234)", v1);
277 /* r2 is allowed to be destroyed because not volatile */
279 xbt_test_fail1("v2=%d (!= 5678)", v2);
284 XBT_TEST_UNIT("cleanup",test_cleanup,"cleanup handling") {
289 xbt_test_add0("cleanup handling");
295 THROW0(1, 2, "blah");
298 xbt_test_fail1("v1 = %d (!= 5678)", v1);
302 xbt_test_fail1("v1 = %d (!= 5678)", v1);
303 if (!(ex.category == 1 && ex.value == 2 && !strcmp(ex.msg,"blah")))
304 xbt_test_fail0("unexpected exception contents");
308 xbt_test_fail0("xbt_ex_free not executed");
313 * The following is the example included in the documentation. It's a good
314 * idea to check its syntax even if we don't try to run it.
315 * And actually, it allows to put comments in the code despite doxygen.
317 static char *mallocex(int size) {
320 #define SMALLAMOUNT 10
321 #define TOOBIG 100000000
323 #if 0 /* this contains syntax errors, actually */
324 static void bad_example(void) {
325 struct {char*first;} *globalcontext;
330 char *cp1, *cp2, *cp3;
332 cp1 = mallocex(SMALLAMOUNT);
333 globalcontext->first = cp1;
334 cp2 = mallocex(TOOBIG);
335 cp3 = mallocex(SMALLAMOUNT);
339 if (cp3 != NULL) free(cp3);
340 if (cp2 != NULL) free(cp2);
341 if (cp1 != NULL) free(cp1);
343 printf("cp3=%s", cp3);
346 /* end_of_bad_example */
349 typedef struct {char *first;} global_context_t;
351 static void good_example(void) {
352 global_context_t *global_context=malloc(sizeof(global_context_t));
357 char * volatile /*03*/ cp1 = NULL /*02*/;
358 char * volatile /*03*/ cp2 = NULL /*02*/;
359 char * volatile /*03*/ cp3 = NULL /*02*/;
361 cp1 = mallocex(SMALLAMOUNT);
362 global_context->first = cp1;
363 cp1 = NULL /*05 give away*/;
364 cp2 = mallocex(TOOBIG);
365 cp3 = mallocex(SMALLAMOUNT);
369 printf("cp3=%s", cp3 == NULL /*02*/ ? "" : cp3);
374 /*05 cp1 was given away */
376 /*05 global context untouched */
380 /* end_of_good_example */
382 #endif /* SIMGRID_TEST */