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_current(xbt_ex_t *e) {
61 xbt_ex_setup_backtrace(e);
65 void xbt_backtrace_display(xbt_ex_t *e) {
70 fprintf(stderr,"(backtrace not set)\n");
72 fprintf(stderr,"Backtrace (displayed in thread %p):\n",
73 (void*)xbt_thread_self());
74 for (i=1; i<e->used; i++) /* no need to display "xbt_display_backtrace" */
75 fprintf(stderr,"---> %s\n",e->bt_strings[i] +4);
78 /* don't fool xbt_ex_free with uninitialized msg field */
84 ERROR0("No backtrace on this arch");
88 /** \brief show the backtrace of the current point (lovely while debuging) */
89 void xbt_backtrace_display_current(void) {
91 xbt_backtrace_current(&e);
92 xbt_backtrace_display(&e);
95 #if defined(HAVE_EXECINFO_H) && defined(HAVE_POPEN) && defined(ADDR2LINE)
96 # include "backtrace_linux.c"
97 #elif (defined(WIN32) && defined (_M_IX86)) && !defined(__GNUC__)
98 # include "backtrace_windows.c"
100 # include "backtrace_dummy.c"
103 /** @brief shows an exception content and the associated stack if available */
104 void xbt_ex_display(xbt_ex_t *e) {
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);
122 if (!e->remote && !e->bt_strings)
123 xbt_ex_setup_backtrace(e);
125 #ifdef HAVE_BACKTRACE
126 /* We have everything to build neat backtraces */
130 fprintf(stderr,"\n");
131 for (i=0; i<e->used; i++)
132 fprintf(stderr,"%s\n",e->bt_strings[i]);
136 fprintf(stderr," at %s:%d:%s (no backtrace available on that arch)\n",
137 e->file,e->line,e->func);
143 /* default __ex_terminate callback function */
144 void __xbt_ex_terminate_default(xbt_ex_t *e) {
150 /* the externally visible API */
151 XBT_EXPORT_NO_IMPORT(ex_ctx_cb_t) __xbt_ex_ctx = &__xbt_ex_ctx_default;
152 XBT_EXPORT_NO_IMPORT(ex_term_cb_t) __xbt_ex_terminate = &__xbt_ex_terminate_default;
155 void xbt_ex_free(xbt_ex_t e) {
158 if (e.msg) free(e.msg);
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) {
177 case unknown_error: return "unknown_err";
178 case arg_error: return "invalid_arg";
179 case mismatch_error: return "mismatch";
180 case not_found_error: return "not found";
181 case system_error: return "system_err";
182 case network_error: return "network_err";
183 case timeout_error: return "timeout";
184 case thread_error: return "thread_err";
185 default: return "INVALID_ERR";
194 XBT_TEST_SUITE("xbt_ex","Exception Handling");
196 XBT_TEST_UNIT("controlflow",test_controlflow, "basic nested control flow") {
200 xbt_test_add0("basic nested control flow");
204 xbt_test_fail1("M1: n=%d (!= 1)", n);
208 xbt_test_fail1("M2: n=%d (!= 2)", n);
210 THROW0(unknown_error,0,"something");
213 xbt_test_fail1("M3: n=%d (!= 3)", n);
220 xbt_test_fail1("M2: n=%d (!= 5)", n);
222 THROW0(unknown_error,0,"something");
225 xbt_test_fail1("M3: n=%d (!= 6)", n);
230 xbt_test_fail1("MX: n=%d (shouldn't reach this point)", n);
234 xbt_test_fail1("M4: n=%d (!= 7)", n);
239 xbt_test_fail1("M5: n=%d (!= 8)", n);
242 XBT_TEST_UNIT("value",test_value,"exception value passing") {
246 THROW0(unknown_error, 2, "toto");
248 xbt_test_add0("exception value passing");
249 if (ex.category != unknown_error)
250 xbt_test_fail1("category=%d (!= 1)", ex.category);
252 xbt_test_fail1("value=%d (!= 2)", ex.value);
253 if (strcmp(ex.msg,"toto"))
254 xbt_test_fail1("message=%s (!= toto)", ex.msg);
259 XBT_TEST_UNIT("variables",test_variables,"variable value preservation") {
264 r1 = r2 = v1 = v2 = 1234;
268 THROW0(unknown_error, 0, "toto");
270 xbt_test_add0("variable preservation");
272 xbt_test_fail1("r1=%d (!= 1234)", r1);
274 xbt_test_fail1("v1=%d (!= 1234)", v1);
275 /* r2 is allowed to be destroyed because not volatile */
277 xbt_test_fail1("v2=%d (!= 5678)", v2);
282 XBT_TEST_UNIT("cleanup",test_cleanup,"cleanup handling") {
287 xbt_test_add0("cleanup handling");
293 THROW0(1, 2, "blah");
296 xbt_test_fail1("v1 = %d (!= 5678)", v1);
300 xbt_test_fail1("v1 = %d (!= 5678)", v1);
301 if (!(ex.category == 1 && ex.value == 2 && !strcmp(ex.msg,"blah")))
302 xbt_test_fail0("unexpected exception contents");
306 xbt_test_fail0("xbt_ex_free not executed");
311 * The following is the example included in the documentation. It's a good
312 * idea to check its syntax even if we don't try to run it.
313 * And actually, it allows to put comments in the code despite doxygen.
315 static char *mallocex(int size) {
318 #define SMALLAMOUNT 10
319 #define TOOBIG 100000000
321 #if 0 /* this contains syntax errors, actually */
322 static void bad_example(void) {
323 struct {char*first;} *globalcontext;
328 char *cp1, *cp2, *cp3;
330 cp1 = mallocex(SMALLAMOUNT);
331 globalcontext->first = cp1;
332 cp2 = mallocex(TOOBIG);
333 cp3 = mallocex(SMALLAMOUNT);
337 if (cp3 != NULL) free(cp3);
338 if (cp2 != NULL) free(cp2);
339 if (cp1 != NULL) free(cp1);
341 printf("cp3=%s", cp3);
344 /* end_of_bad_example */
347 typedef struct {char *first;} global_context_t;
349 static void good_example(void) {
350 global_context_t *global_context=malloc(sizeof(global_context_t));
355 char * volatile /*03*/ cp1 = NULL /*02*/;
356 char * volatile /*03*/ cp2 = NULL /*02*/;
357 char * volatile /*03*/ cp3 = NULL /*02*/;
359 cp1 = mallocex(SMALLAMOUNT);
360 global_context->first = cp1;
361 cp1 = NULL /*05 give away*/;
362 cp2 = mallocex(TOOBIG);
363 cp3 = mallocex(SMALLAMOUNT);
367 printf("cp3=%s", cp3 == NULL /*02*/ ? "" : cp3);
372 /*05 cp1 was given away */
374 /*05 global context untouched */
378 /* end_of_good_example */
380 #endif /* SIMGRID_TEST */