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);
118 if (!e->remote && !e->bt_strings)
119 xbt_ex_setup_backtrace(e);
121 #ifdef HAVE_BACKTRACE
122 /* We have everything to build neat backtraces */
126 fprintf(stderr,"\n");
127 for (i=0; i<e->used; i++)
128 fprintf(stderr,"%s\n",e->bt_strings[i]);
132 fprintf(stderr," at %s:%d:%s (no backtrace available on that arch)\n",
133 e->file,e->line,e->func);
139 /* default __ex_terminate callback function */
140 void __xbt_ex_terminate_default(xbt_ex_t *e) {
146 /* the externally visible API */
147 XBT_EXPORT_NO_IMPORT(ex_ctx_cb_t) __xbt_ex_ctx = &__xbt_ex_ctx_default;
148 XBT_EXPORT_NO_IMPORT(ex_term_cb_t) __xbt_ex_terminate = &__xbt_ex_terminate_default;
151 void xbt_ex_free(xbt_ex_t e) {
154 if (e.msg) free(e.msg);
163 for (i=0; i<e.used; i++)
164 free((char*)e.bt_strings[i]);
165 free((char **)e.bt_strings);
167 /* memset(e,0,sizeof(xbt_ex_t)); */
170 /** \brief returns a short name for the given exception category */
171 const char * xbt_ex_catname(xbt_errcat_t cat) {
173 case unknown_error: return "unknown_err";
174 case arg_error: return "invalid_arg";
175 case mismatch_error: return "mismatch";
176 case not_found_error: return "not found";
177 case system_error: return "system_err";
178 case network_error: return "network_err";
179 case timeout_error: return "timeout";
180 case thread_error: return "thread_err";
181 default: return "INVALID_ERR";
190 XBT_TEST_SUITE("xbt_ex","Exception Handling");
192 XBT_TEST_UNIT("controlflow",test_controlflow, "basic nested control flow") {
196 xbt_test_add0("basic nested control flow");
200 xbt_test_fail1("M1: n=%d (!= 1)", n);
204 xbt_test_fail1("M2: n=%d (!= 2)", n);
206 THROW0(unknown_error,0,"something");
209 xbt_test_fail1("M3: n=%d (!= 3)", n);
216 xbt_test_fail1("M2: n=%d (!= 5)", n);
218 THROW0(unknown_error,0,"something");
221 xbt_test_fail1("M3: n=%d (!= 6)", n);
226 xbt_test_fail1("MX: n=%d (shouldn't reach this point)", n);
230 xbt_test_fail1("M4: n=%d (!= 7)", n);
235 xbt_test_fail1("M5: n=%d (!= 8)", n);
238 XBT_TEST_UNIT("value",test_value,"exception value passing") {
242 THROW0(unknown_error, 2, "toto");
244 xbt_test_add0("exception value passing");
245 if (ex.category != unknown_error)
246 xbt_test_fail1("category=%d (!= 1)", ex.category);
248 xbt_test_fail1("value=%d (!= 2)", ex.value);
249 if (strcmp(ex.msg,"toto"))
250 xbt_test_fail1("message=%s (!= toto)", ex.msg);
255 XBT_TEST_UNIT("variables",test_variables,"variable value preservation") {
260 r1 = r2 = v1 = v2 = 1234;
264 THROW0(unknown_error, 0, "toto");
266 xbt_test_add0("variable preservation");
268 xbt_test_fail1("r1=%d (!= 1234)", r1);
270 xbt_test_fail1("v1=%d (!= 1234)", v1);
271 /* r2 is allowed to be destroyed because not volatile */
273 xbt_test_fail1("v2=%d (!= 5678)", v2);
278 XBT_TEST_UNIT("cleanup",test_cleanup,"cleanup handling") {
283 xbt_test_add0("cleanup handling");
289 THROW0(1, 2, "blah");
292 xbt_test_fail1("v1 = %d (!= 5678)", v1);
296 xbt_test_fail1("v1 = %d (!= 5678)", v1);
297 if (!(ex.category == 1 && ex.value == 2 && !strcmp(ex.msg,"blah")))
298 xbt_test_fail0("unexpected exception contents");
302 xbt_test_fail0("xbt_ex_free not executed");
307 * The following is the example included in the documentation. It's a good
308 * idea to check its syntax even if we don't try to run it.
309 * And actually, it allows to put comments in the code despite doxygen.
311 static char *mallocex(int size) {
314 #define SMALLAMOUNT 10
315 #define TOOBIG 100000000
317 #if 0 /* this contains syntax errors, actually */
318 static void bad_example(void) {
319 struct {char*first;} *globalcontext;
324 char *cp1, *cp2, *cp3;
326 cp1 = mallocex(SMALLAMOUNT);
327 globalcontext->first = cp1;
328 cp2 = mallocex(TOOBIG);
329 cp3 = mallocex(SMALLAMOUNT);
333 if (cp3 != NULL) free(cp3);
334 if (cp2 != NULL) free(cp2);
335 if (cp1 != NULL) free(cp1);
337 printf("cp3=%s", cp3);
340 /* end_of_bad_example */
343 typedef struct {char *first;} global_context_t;
345 static void good_example(void) {
346 global_context_t *global_context=malloc(sizeof(global_context_t));
351 char * volatile /*03*/ cp1 = NULL /*02*/;
352 char * volatile /*03*/ cp2 = NULL /*02*/;
353 char * volatile /*03*/ cp3 = NULL /*02*/;
355 cp1 = mallocex(SMALLAMOUNT);
356 global_context->first = cp1;
357 cp1 = NULL /*05 give away*/;
358 cp2 = mallocex(TOOBIG);
359 cp3 = mallocex(SMALLAMOUNT);
363 printf("cp3=%s", cp3 == NULL /*02*/ ? "" : cp3);
368 /*05 cp1 was given away */
370 /*05 global context untouched */
374 /* end_of_good_example */
376 #endif /* SIMGRID_TEST */