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);
65 fprintf(stderr,"(backtrace not set)\n");
67 fprintf(stderr,"Backtrace (displayed in thread %p):\n",
68 (void*)xbt_thread_self());
69 for (i=1; i<e->used; i++) /* no need to display "xbt_display_backtrace" */
70 fprintf(stderr,"---> %s\n",e->bt_strings[i] +4);
73 /* don't fool xbt_ex_free with uninitialized msg field */
79 ERROR0("No backtrace on this arch");
83 /** \brief show the backtrace of the current point (lovely while debuging) */
84 void xbt_backtrace_display_current(void) {
86 xbt_backtrace_current(&e);
87 xbt_backtrace_display(&e);
90 #if defined(HAVE_EXECINFO_H) && defined(HAVE_POPEN) && defined(ADDR2LINE)
91 # include "backtrace_linux.c"
92 #elif (defined(WIN32) && defined (_M_IX86)) && !defined(__GNUC__)
93 # include "backtrace_windows.c"
95 # include "backtrace_dummy.c"
98 /** @brief shows an exception content and the associated stack if available */
99 void xbt_ex_display(xbt_ex_t *e) {
103 thrower = bprintf(" on host %s(%d)",e->host,e->pid);
106 "** SimGrid: UNCAUGHT EXCEPTION received on %s(%d): category: %s; value: %d\n"
108 "** Thrown by %s()%s\n",
109 gras_os_myname(),(*xbt_getpid)(),
110 xbt_ex_catname(e->category), e->value, e->msg,
111 e->procname,thrower?thrower:" in this process");
112 CRITICAL1("%s",e->msg);
117 if (!e->remote && !e->bt_strings)
118 xbt_ex_setup_backtrace(e);
120 #ifdef HAVE_BACKTRACE
121 /* We have everything to build neat backtraces */
125 fprintf(stderr,"\n");
126 for (i=0; i<e->used; i++)
127 fprintf(stderr,"%s\n",e->bt_strings[i]);
131 fprintf(stderr," at %s:%d:%s (no backtrace available on that arch)\n",
132 e->file,e->line,e->func);
138 /* default __ex_terminate callback function */
139 void __xbt_ex_terminate_default(xbt_ex_t *e) {
145 /* the externally visible API */
146 XBT_EXPORT_NO_IMPORT(ex_ctx_cb_t) __xbt_ex_ctx = &__xbt_ex_ctx_default;
147 XBT_EXPORT_NO_IMPORT(ex_term_cb_t) __xbt_ex_terminate = &__xbt_ex_terminate_default;
150 void xbt_ex_free(xbt_ex_t e) {
153 if (e.msg) free(e.msg);
162 for (i=0; i<e.used; i++)
163 free((char*)e.bt_strings[i]);
164 free((char **)e.bt_strings);
166 /* memset(e,0,sizeof(xbt_ex_t)); */
169 /** \brief returns a short name for the given exception category */
170 const char * xbt_ex_catname(xbt_errcat_t cat) {
172 case unknown_error: return "unknown_err";
173 case arg_error: return "invalid_arg";
174 case mismatch_error: return "mismatch";
175 case not_found_error: return "not found";
176 case system_error: return "system_err";
177 case network_error: return "network_err";
178 case timeout_error: return "timeout";
179 case thread_error: return "thread_err";
180 default: return "INVALID_ERR";
189 XBT_TEST_SUITE("xbt_ex","Exception Handling");
191 XBT_TEST_UNIT("controlflow",test_controlflow, "basic nested control flow") {
195 xbt_test_add0("basic nested control flow");
199 xbt_test_fail1("M1: n=%d (!= 1)", n);
203 xbt_test_fail1("M2: n=%d (!= 2)", n);
205 THROW0(unknown_error,0,"something");
208 xbt_test_fail1("M3: n=%d (!= 3)", n);
215 xbt_test_fail1("M2: n=%d (!= 5)", n);
217 THROW0(unknown_error,0,"something");
220 xbt_test_fail1("M3: n=%d (!= 6)", n);
225 xbt_test_fail1("MX: n=%d (shouldn't reach this point)", n);
229 xbt_test_fail1("M4: n=%d (!= 7)", n);
234 xbt_test_fail1("M5: n=%d (!= 8)", n);
237 XBT_TEST_UNIT("value",test_value,"exception value passing") {
241 THROW0(unknown_error, 2, "toto");
243 xbt_test_add0("exception value passing");
244 if (ex.category != unknown_error)
245 xbt_test_fail1("category=%d (!= 1)", ex.category);
247 xbt_test_fail1("value=%d (!= 2)", ex.value);
248 if (strcmp(ex.msg,"toto"))
249 xbt_test_fail1("message=%s (!= toto)", ex.msg);
254 XBT_TEST_UNIT("variables",test_variables,"variable value preservation") {
259 r1 = r2 = v1 = v2 = 1234;
263 THROW0(unknown_error, 0, "toto");
265 xbt_test_add0("variable preservation");
267 xbt_test_fail1("r1=%d (!= 1234)", r1);
269 xbt_test_fail1("v1=%d (!= 1234)", v1);
270 /* r2 is allowed to be destroyed because not volatile */
272 xbt_test_fail1("v2=%d (!= 5678)", v2);
277 XBT_TEST_UNIT("cleanup",test_cleanup,"cleanup handling") {
282 xbt_test_add0("cleanup handling");
288 THROW0(1, 2, "blah");
291 xbt_test_fail1("v1 = %d (!= 5678)", v1);
295 xbt_test_fail1("v1 = %d (!= 5678)", v1);
296 if (!(ex.category == 1 && ex.value == 2 && !strcmp(ex.msg,"blah")))
297 xbt_test_fail0("unexpected exception contents");
301 xbt_test_fail0("xbt_ex_free not executed");
306 * The following is the example included in the documentation. It's a good
307 * idea to check its syntax even if we don't try to run it.
308 * And actually, it allows to put comments in the code despite doxygen.
310 static char *mallocex(int size) {
313 #define SMALLAMOUNT 10
314 #define TOOBIG 100000000
316 #if 0 /* this contains syntax errors, actually */
317 static void bad_example(void) {
318 struct {char*first;} *globalcontext;
323 char *cp1, *cp2, *cp3;
325 cp1 = mallocex(SMALLAMOUNT);
326 globalcontext->first = cp1;
327 cp2 = mallocex(TOOBIG);
328 cp3 = mallocex(SMALLAMOUNT);
332 if (cp3 != NULL) free(cp3);
333 if (cp2 != NULL) free(cp2);
334 if (cp1 != NULL) free(cp1);
336 printf("cp3=%s", cp3);
339 /* end_of_bad_example */
342 typedef struct {char *first;} global_context_t;
344 static void good_example(void) {
345 global_context_t *global_context=malloc(sizeof(global_context_t));
350 char * volatile /*03*/ cp1 = NULL /*02*/;
351 char * volatile /*03*/ cp2 = NULL /*02*/;
352 char * volatile /*03*/ cp3 = NULL /*02*/;
354 cp1 = mallocex(SMALLAMOUNT);
355 global_context->first = cp1;
356 cp1 = NULL /*05 give away*/;
357 cp2 = mallocex(TOOBIG);
358 cp3 = mallocex(SMALLAMOUNT);
362 printf("cp3=%s", cp3 == NULL /*02*/ ? "" : cp3);
367 /*05 cp1 was given away */
369 /*05 global context untouched */
373 /* end_of_good_example */
375 #endif /* SIMGRID_TEST */