Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
SMPI: Change the reference speed to a command line option
[simgrid.git] / src / xbt / ex.c
1 /* $Id$ */
2
3 /* ex - Exception Handling (modified to fit into SimGrid from OSSP version) */
4
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.                                                    */
10
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. */
13
14 #include <stdio.h>
15 #include <stdlib.h>
16
17 #include "portable.h"           /* execinfo when available */
18 #include "xbt/ex.h"
19 #include "xbt/str.h"
20 #include "xbt/module.h"         /* xbt_binary_name */
21 #include "xbt_modinter.h"       /* backtrace initialization headers */
22 #include "xbt/synchro.h"        /* xbt_thread_self */
23
24 #include "gras/Virtu/virtu_interface.h" /* gras_os_myname */
25 #include "xbt/ex_interface.h"
26
27 #undef HAVE_BACKTRACE
28 #if defined(HAVE_EXECINFO_H) && defined(HAVE_POPEN) && defined(ADDR2LINE)
29 # define HAVE_BACKTRACE 1       /* Hello linux box */
30 #endif
31
32 #if defined(WIN32) && defined(_M_IX86) && !defined(__GNUC__)
33 # define HAVE_BACKTRACE 1       /* Hello x86 windows box */
34 #endif
35
36
37 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(xbt_ex, xbt, "Exception mecanism");
38
39 /* default __ex_ctx callback function */
40 ex_ctx_t *__xbt_ex_ctx_default(void)
41 {
42   /* Don't scream: this is a default which is never used (so, yes,
43      there is one setjump container by running entity).
44
45      This default gets overriden in xbt/xbt_os_thread.c so that it works in
46      real life and in simulation when using threads to implement the simulation
47      processes (ie, with pthreads and on windows).
48
49      It also gets overriden in xbt/context.c when using ucontextes (as well as
50      in Java for now, but after the java overhaul, it will get cleaned out)
51    */
52   static ex_ctx_t ctx = XBT_CTX_INITIALIZER;
53
54   return &ctx;
55 }
56
57 /* Change raw libc symbols to file names and line numbers */
58 void xbt_ex_setup_backtrace(xbt_ex_t * e);
59
60 void xbt_backtrace_display(xbt_ex_t * e)
61 {
62   xbt_ex_setup_backtrace(e);
63
64 #ifdef HAVE_BACKTRACE
65   if (e->used == 0) {
66     fprintf(stderr, "(backtrace not set)\n");
67   } else {
68     int i;
69
70     fprintf(stderr, "Backtrace (displayed in thread %p):\n",
71             (void *) xbt_thread_self());
72     for (i = 1; i < e->used; i++)       /* no need to display "xbt_display_backtrace" */
73       fprintf(stderr, "---> %s\n", e->bt_strings[i] + 4);
74   }
75
76   /* don't fool xbt_ex_free with uninitialized msg field */
77   e->msg = NULL;
78   e->remote = 0;
79   xbt_ex_free(*e);
80 #else
81
82   ERROR0("No backtrace on this arch");
83 #endif
84 }
85
86 /** \brief show the backtrace of the current point (lovely while debuging) */
87 void xbt_backtrace_display_current(void)
88 {
89   xbt_ex_t e;
90   xbt_backtrace_current(&e);
91   xbt_backtrace_display(&e);
92 }
93
94 #if defined(HAVE_EXECINFO_H) && defined(HAVE_POPEN) && defined(ADDR2LINE)
95 # include "backtrace_linux.c"
96 #elif (defined(WIN32) && defined (_M_IX86)) && !defined(__GNUC__)
97 # include "backtrace_windows.c"
98 #else
99 # include "backtrace_dummy.c"
100 #endif
101
102 /** @brief shows an exception content and the associated stack if available */
103 void xbt_ex_display(xbt_ex_t * e)
104 {
105   char *thrower = NULL;
106
107   if (e->remote)
108     thrower = bprintf(" on host %s(%d)", e->host, e->pid);
109
110   fprintf(stderr,
111           "** SimGrid: UNCAUGHT EXCEPTION received on %s(%d): category: %s; value: %d\n"
112           "** %s\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);
118
119   if (!e->remote && !e->bt_strings)
120     xbt_ex_setup_backtrace(e);
121
122 #ifdef HAVE_BACKTRACE
123   /* We have everything to build neat backtraces */
124   {
125     int i;
126
127     fprintf(stderr, "\n");
128     for (i = 0; i < e->used; i++)
129       fprintf(stderr, "%s\n", e->bt_strings[i]);
130
131   }
132 #else
133   fprintf(stderr, " at %s:%d:%s (no backtrace available on that arch)\n",
134           e->file, e->line, e->func);
135 #endif
136 }
137
138
139 /* default __ex_terminate callback function */
140 void __xbt_ex_terminate_default(xbt_ex_t * e)
141 {
142   xbt_ex_display(e);
143
144   abort();
145 }
146
147 /* the externally visible API */
148 XBT_EXPORT_NO_IMPORT(ex_ctx_cb_t) __xbt_ex_ctx = &__xbt_ex_ctx_default;
149 XBT_EXPORT_NO_IMPORT(ex_term_cb_t) __xbt_ex_terminate =
150   &__xbt_ex_terminate_default;
151
152
153      void xbt_ex_free(xbt_ex_t e)
154 {
155   int i;
156
157   if (e.msg)
158     free(e.msg);
159   if (e.remote) {
160     free(e.procname);
161     free(e.file);
162     free(e.func);
163     free(e.host);
164   }
165
166   if (e.bt_strings) {
167     for (i = 0; i < e.used; i++)
168       free((char *) e.bt_strings[i]);
169     free((char **) e.bt_strings);
170   }
171   /* memset(e,0,sizeof(xbt_ex_t)); */
172 }
173
174 /** \brief returns a short name for the given exception category */
175 const char *xbt_ex_catname(xbt_errcat_t cat)
176 {
177   switch (cat) {
178   case unknown_error:
179     return "unknown_err";
180   case arg_error:
181     return "invalid_arg";
182   case mismatch_error:
183     return "mismatch";
184   case not_found_error:
185     return "not found";
186   case system_error:
187     return "system_err";
188   case network_error:
189     return "network_err";
190   case timeout_error:
191     return "timeout";
192   case thread_error:
193     return "thread_err";
194   default:
195     return "INVALID_ERR";
196   }
197 }
198
199
200 #ifdef SIMGRID_TEST
201 #include <stdio.h>
202 #include "xbt/ex.h"
203
204 XBT_TEST_SUITE("xbt_ex", "Exception Handling");
205
206 XBT_TEST_UNIT("controlflow", test_controlflow, "basic nested control flow")
207 {
208   xbt_ex_t ex;
209   volatile int n = 1;
210
211   xbt_test_add0("basic nested control flow");
212
213   TRY {
214     if (n != 1)
215       xbt_test_fail1("M1: n=%d (!= 1)", n);
216     n++;
217     TRY {
218       if (n != 2)
219         xbt_test_fail1("M2: n=%d (!= 2)", n);
220       n++;
221       THROW0(unknown_error, 0, "something");
222     }
223     CATCH(ex) {
224       if (n != 3)
225         xbt_test_fail1("M3: n=%d (!= 3)", n);
226       n++;
227       xbt_ex_free(ex);
228     }
229     n++;
230     TRY {
231       if (n != 5)
232         xbt_test_fail1("M2: n=%d (!= 5)", n);
233       n++;
234       THROW0(unknown_error, 0, "something");
235     }
236     CATCH(ex) {
237       if (n != 6)
238         xbt_test_fail1("M3: n=%d (!= 6)", n);
239       n++;
240       RETHROW;
241       n++;
242     }
243     xbt_test_fail1("MX: n=%d (shouldn't reach this point)", n);
244   }
245   CATCH(ex) {
246     if (n != 7)
247       xbt_test_fail1("M4: n=%d (!= 7)", n);
248     n++;
249     xbt_ex_free(ex);
250   }
251   if (n != 8)
252     xbt_test_fail1("M5: n=%d (!= 8)", n);
253 }
254
255 XBT_TEST_UNIT("value", test_value, "exception value passing")
256 {
257   xbt_ex_t ex;
258
259   TRY {
260     THROW0(unknown_error, 2, "toto");
261   }
262   CATCH(ex) {
263     xbt_test_add0("exception value passing");
264     if (ex.category != unknown_error)
265       xbt_test_fail1("category=%d (!= 1)", ex.category);
266     if (ex.value != 2)
267       xbt_test_fail1("value=%d (!= 2)", ex.value);
268     if (strcmp(ex.msg, "toto"))
269       xbt_test_fail1("message=%s (!= toto)", ex.msg);
270     xbt_ex_free(ex);
271   }
272 }
273
274 XBT_TEST_UNIT("variables", test_variables, "variable value preservation")
275 {
276   xbt_ex_t ex;
277   int r1, r2;
278   volatile int v1, v2;
279
280   r1 = r2 = v1 = v2 = 1234;
281   TRY {
282     r2 = 5678;
283     v2 = 5678;
284     THROW0(unknown_error, 0, "toto");
285   } CATCH(ex) {
286     xbt_test_add0("variable preservation");
287     if (r1 != 1234)
288       xbt_test_fail1("r1=%d (!= 1234)", r1);
289     if (v1 != 1234)
290       xbt_test_fail1("v1=%d (!= 1234)", v1);
291     /* r2 is allowed to be destroyed because not volatile */
292     if (v2 != 5678)
293       xbt_test_fail1("v2=%d (!= 5678)", v2);
294     xbt_ex_free(ex);
295   }
296 }
297
298 XBT_TEST_UNIT("cleanup", test_cleanup, "cleanup handling")
299 {
300   xbt_ex_t ex;
301   volatile int v1;
302   int c;
303
304   xbt_test_add0("cleanup handling");
305
306   v1 = 1234;
307   c = 0;
308   TRY {
309     v1 = 5678;
310     THROW0(1, 2, "blah");
311   } CLEANUP {
312     if (v1 != 5678)
313       xbt_test_fail1("v1 = %d (!= 5678)", v1);
314     c = 1;
315   }
316   CATCH(ex) {
317     if (v1 != 5678)
318       xbt_test_fail1("v1 = %d (!= 5678)", v1);
319     if (!(ex.category == 1 && ex.value == 2 && !strcmp(ex.msg, "blah")))
320       xbt_test_fail0("unexpected exception contents");
321     xbt_ex_free(ex);
322   }
323   if (!c)
324     xbt_test_fail0("xbt_ex_free not executed");
325 }
326
327
328 /*
329  * The following is the example included in the documentation. It's a good
330  * idea to check its syntax even if we don't try to run it.
331  * And actually, it allows to put comments in the code despite doxygen.
332  */
333 static char *mallocex(int size)
334 {
335   return NULL;
336 }
337
338 #define SMALLAMOUNT 10
339 #define TOOBIG 100000000
340
341 #if 0                           /* this contains syntax errors, actually */
342 static void bad_example(void)
343 {
344   struct {
345     char *first;
346   } *globalcontext;
347   ex_t ex;
348
349   /* BAD_EXAMPLE */
350   TRY {
351     char *cp1, *cp2, *cp3;
352
353     cp1 = mallocex(SMALLAMOUNT);
354     globalcontext->first = cp1;
355     cp2 = mallocex(TOOBIG);
356     cp3 = mallocex(SMALLAMOUNT);
357     strcpy(cp1, "foo");
358     strcpy(cp2, "bar");
359   } CLEANUP {
360     if (cp3 != NULL)
361       free(cp3);
362     if (cp2 != NULL)
363       free(cp2);
364     if (cp1 != NULL)
365       free(cp1);
366   }
367   CATCH(ex) {
368     printf("cp3=%s", cp3);
369     RETHROW;
370   }
371   /* end_of_bad_example */
372 }
373 #endif
374 typedef struct {
375   char *first;
376 } global_context_t;
377
378 static void good_example(void)
379 {
380   global_context_t *global_context = malloc(sizeof(global_context_t));
381   xbt_ex_t ex;
382
383   /* GOOD_EXAMPLE */
384   {                             /*01 */
385     char *volatile /*03 */ cp1 = NULL /*02 */ ;
386     char *volatile /*03 */ cp2 = NULL /*02 */ ;
387     char *volatile /*03 */ cp3 = NULL /*02 */ ;
388     TRY {
389       cp1 = mallocex(SMALLAMOUNT);
390       global_context->first = cp1;
391       cp1 = NULL /*05 give away */ ;
392       cp2 = mallocex(TOOBIG);
393       cp3 = mallocex(SMALLAMOUNT);
394       strcpy(cp1, "foo");
395       strcpy(cp2, "bar");
396     } CLEANUP {                 /*04 */
397       printf("cp3=%s", cp3 == NULL /*02 */ ? "" : cp3);
398       if (cp3 != NULL)
399         free(cp3);
400       if (cp2 != NULL)
401         free(cp2);
402       /*05 cp1 was given away */
403     }
404     CATCH(ex) {
405       /*05 global context untouched */
406       RETHROW;
407     }
408   }
409   /* end_of_good_example */
410 }
411 #endif /* SIMGRID_TEST */