Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
9768d5e6402031d45a7de6420c7e06f5b0850500
[simgrid.git] / src / xbt / ex.c
1 /* ex - Exception Handling                                                  */
2
3 /*  Copyright (c) 2005-2010 The SimGrid team                                */
4 /*  Copyright (c) 2002-2004 Ralf S. Engelschall <rse@engelschall.com>       */
5 /*  Copyright (c) 2002-2004 The OSSP Project <http://www.ossp.org/>         */
6 /*  Copyright (c) 2002-2004 Cable & Wireless <http://www.cw.com/>           */
7 /*  All rights reserved.                                                    */
8
9 /* This code is inspirated from the OSSP version (as retrieved back in 2004)*/
10 /* It was heavily modified to fit the SimGrid framework.                    */
11
12 /* The OSSP version has the following copyright notice:
13 **  OSSP ex - Exception Handling
14 **  Copyright (c) 2002-2004 Ralf S. Engelschall <rse@engelschall.com>
15 **  Copyright (c) 2002-2004 The OSSP Project <http://www.ossp.org/>
16 **  Copyright (c) 2002-2004 Cable & Wireless <http://www.cw.com/>
17 **
18 **  This file is part of OSSP ex, an exception handling library
19 **  which can be found at http://www.ossp.org/pkg/lib/ex/.
20 **
21 **  Permission to use, copy, modify, and distribute this software for
22 **  any purpose with or without fee is hereby granted, provided that
23 **  the above copyright notice and this permission notice appear in all
24 **  copies.
25 **
26 **  THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESSED OR IMPLIED
27 **  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
28 **  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29 **  IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
30 **  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31 **  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32 **  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
33 **  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
34 **  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
35 **  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
36 **  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 **  SUCH DAMAGE.
38  */
39
40 /* The extensions made for the SimGrid project can either be distributed    */
41 /* under the same license, or under the LGPL v2.1                           */
42
43 #include <stdio.h>
44 #include <stdlib.h>
45
46 #include "portable.h"           /* execinfo when available */
47 #include "xbt/ex.h"
48 #include "xbt/str.h"
49 #include "xbt/module.h"         /* xbt_binary_name */
50 #include "xbt_modinter.h"       /* backtrace initialization headers */
51 #include "xbt/synchro.h"        /* xbt_thread_self */
52
53 #include "gras/Virtu/virtu_interface.h" /* gras_os_myname */
54 #include "xbt/ex_interface.h"
55
56 #undef HAVE_BACKTRACE
57 #if defined(HAVE_EXECINFO_H) && defined(HAVE_POPEN) && defined(ADDR2LINE)
58 # define HAVE_BACKTRACE 1       /* Hello linux box */
59 #endif
60
61 #if defined(_XBT_WIN32) && defined(_M_IX86) && !defined(__GNUC__)
62 # define HAVE_BACKTRACE 1       /* Hello x86 windows box */
63 #endif
64
65
66 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(xbt_ex, xbt, "Exception mecanism");
67
68 /* default __ex_ctx callback function */
69 xbt_running_ctx_t *__xbt_ex_ctx_default(void)
70 {
71   /* Don't scream: this is a default which is never used (so, yes,
72      there is one setjump container by running entity).
73
74      This default gets overriden in xbt/xbt_os_thread.c so that it works in
75      real life and in simulation when using threads to implement the simulation
76      processes (ie, with pthreads and on windows).
77
78      It also gets overriden in xbt/context.c when using ucontextes (as well as
79      in Java for now, but after the java overhaul, it will get cleaned out)
80    */
81   static xbt_running_ctx_t ctx = XBT_RUNNING_CTX_INITIALIZER;
82
83   return &ctx;
84 }
85
86 /* Change raw libc symbols to file names and line numbers */
87 void xbt_ex_setup_backtrace(xbt_ex_t * e);
88
89 void xbt_backtrace_display(xbt_ex_t * e)
90 {
91   xbt_ex_setup_backtrace(e);
92
93 #ifdef HAVE_BACKTRACE
94   if (e->used == 0) {
95     fprintf(stderr, "(backtrace not set)\n");
96   } else {
97     int i;
98
99     fprintf(stderr, "Backtrace (displayed in thread %p):\n",
100             (void *) xbt_thread_self());
101     for (i = 1; i < e->used; i++)       /* no need to display "xbt_backtrace_display" */
102       fprintf(stderr, "---> %s\n", e->bt_strings[i] + 4);
103   }
104
105   /* don't fool xbt_ex_free with uninitialized msg field */
106   e->msg = NULL;
107   e->remote = 0;
108   xbt_ex_free(*e);
109 #else
110
111   XBT_ERROR("No backtrace on this arch");
112 #endif
113 }
114
115 /** \brief show the backtrace of the current point (lovely while debuging) */
116 void xbt_backtrace_display_current(void)
117 {
118   xbt_ex_t e;
119   xbt_backtrace_current(&e);
120   xbt_backtrace_display(&e);
121 }
122
123 #if defined(HAVE_EXECINFO_H) && defined(HAVE_POPEN) && defined(ADDR2LINE)
124 # include "backtrace_linux.c"
125 #elif (defined(_XBT_WIN32) && defined (_M_IX86)) && !defined(__GNUC__)
126 # include "backtrace_windows.c"
127 #else
128 # include "backtrace_dummy.c"
129 #endif
130
131 /** @brief shows an exception content and the associated stack if available */
132 void xbt_ex_display(xbt_ex_t * e)
133 {
134   char *thrower = NULL;
135
136   if (e->remote)
137     thrower = bprintf(" on host %s(%d)", e->host, e->pid);
138
139   fprintf(stderr,
140           "** SimGrid: UNCAUGHT EXCEPTION received on %s(%d): category: %s; value: %d\n"
141           "** %s\n"
142           "** Thrown by %s()%s\n",
143           gras_os_myname(), xbt_getpid(),
144           xbt_ex_catname(e->category), e->value, e->msg,
145           e->procname, thrower ? thrower : " in this process");
146   XBT_CRITICAL("%s", e->msg);
147
148   if (!e->remote && !e->bt_strings)
149     xbt_ex_setup_backtrace(e);
150
151 #ifdef HAVE_BACKTRACE
152   /* We have everything to build neat backtraces */
153   {
154     int i;
155
156     if (!xbt_binary_name) {
157       fprintf(stderr, "variable 'xbt_binary_name' set to NULL. Cannot compute the backtrace\n");
158       return;
159     }
160     fprintf(stderr, "\n");
161     for (i = 0; i < e->used; i++)
162       fprintf(stderr, "%s\n", e->bt_strings[i]);
163
164   }
165 #else
166   fprintf(stderr, " at %s:%d:%s (no backtrace available on that arch)\n",
167           e->file, e->line, e->func);
168 #endif
169 }
170
171
172 /* default __ex_terminate callback function */
173 void __xbt_ex_terminate_default(xbt_ex_t * e)
174 {
175   xbt_ex_display(e);
176
177   abort();
178 }
179
180 /* the externally visible API */
181 XBT_EXPORT_NO_IMPORT(xbt_running_ctx_fetcher_t) __xbt_running_ctx_fetch = &__xbt_ex_ctx_default;
182 XBT_EXPORT_NO_IMPORT(ex_term_cb_t) __xbt_ex_terminate =
183     &__xbt_ex_terminate_default;
184
185
186 void xbt_ex_free(xbt_ex_t e)
187 {
188   int i;
189
190   free(e.msg);
191   if (e.remote) {
192     free(e.procname);
193     free(e.file);
194     free(e.func);
195     free(e.host);
196   }
197
198   if (e.bt_strings) {
199     for (i = 0; i < e.used; i++)
200       free(e.bt_strings[i]);
201     free(e.bt_strings);
202   }
203   /* memset(e,0,sizeof(xbt_ex_t)); */
204 }
205
206 /** \brief returns a short name for the given exception category */
207 const char *xbt_ex_catname(xbt_errcat_t cat)
208 {
209   switch (cat) {
210   case unknown_error:
211     return "unknown_err";
212   case arg_error:
213     return "invalid_arg";
214   case mismatch_error:
215     return "mismatch";
216   case not_found_error:
217     return "not found";
218   case system_error:
219     return "system_err";
220   case network_error:
221     return "network_err";
222   case timeout_error:
223     return "timeout";
224   case thread_error:
225     return "thread_err";
226   default:
227     return "INVALID_ERR";
228   }
229 }
230
231
232 #ifdef SIMGRID_TEST
233 #include <stdio.h>
234 #include "xbt/ex.h"
235
236 XBT_TEST_SUITE("xbt_ex", "Exception Handling");
237
238 XBT_TEST_UNIT("controlflow", test_controlflow, "basic nested control flow")
239 {
240   xbt_ex_t ex;
241   volatile int n = 1;
242
243   xbt_test_add("basic nested control flow");
244
245   TRY {
246     if (n != 1)
247       xbt_test_fail("M1: n=%d (!= 1)", n);
248     n++;
249     TRY {
250       if (n != 2)
251         xbt_test_fail("M2: n=%d (!= 2)", n);
252       n++;
253       THROWF(unknown_error, 0, "something");
254     }
255     CATCH(ex) {
256       if (n != 3)
257         xbt_test_fail("M3: n=%d (!= 3)", n);
258       n++;
259       xbt_ex_free(ex);
260     }
261     n++;
262     TRY {
263       if (n != 5)
264         xbt_test_fail("M2: n=%d (!= 5)", n);
265       n++;
266       THROWF(unknown_error, 0, "something");
267     }
268     CATCH_ANONYMOUS {
269       if (n != 6)
270         xbt_test_fail("M3: n=%d (!= 6)", n);
271       n++;
272       RETHROW;
273       n++;
274     }
275     xbt_test_fail("MX: n=%d (shouldn't reach this point)", n);
276   }
277   CATCH(ex) {
278     if (n != 7)
279       xbt_test_fail("M4: n=%d (!= 7)", n);
280     n++;
281     xbt_ex_free(ex);
282   }
283   if (n != 8)
284     xbt_test_fail("M5: n=%d (!= 8)", n);
285 }
286
287 XBT_TEST_UNIT("value", test_value, "exception value passing")
288 {
289   xbt_ex_t ex;
290
291   TRY {
292     THROWF(unknown_error, 2, "toto");
293   }
294   CATCH(ex) {
295     xbt_test_add("exception value passing");
296     if (ex.category != unknown_error)
297       xbt_test_fail("category=%d (!= 1)", ex.category);
298     if (ex.value != 2)
299       xbt_test_fail("value=%d (!= 2)", ex.value);
300     if (strcmp(ex.msg, "toto"))
301       xbt_test_fail("message=%s (!= toto)", ex.msg);
302     xbt_ex_free(ex);
303   }
304 }
305
306 XBT_TEST_UNIT("variables", test_variables, "variable value preservation")
307 {
308   xbt_ex_t ex;
309   int r1, r2;
310   volatile int v1, v2;
311
312   r1 = r2 = v1 = v2 = 1234;
313   TRY {
314     r2 = 5678;
315     v2 = 5678;
316     THROWF(unknown_error, 0, "toto");
317   }
318   CATCH(ex) {
319     xbt_test_add("variable preservation");
320     if (r1 != 1234)
321       xbt_test_fail("r1=%d (!= 1234)", r1);
322     if (v1 != 1234)
323       xbt_test_fail("v1=%d (!= 1234)", v1);
324     /* r2 is allowed to be destroyed because not volatile */
325     if (v2 != 5678)
326       xbt_test_fail("v2=%d (!= 5678)", v2);
327     xbt_ex_free(ex);
328   }
329 }
330
331 XBT_TEST_UNIT("cleanup", test_cleanup, "cleanup handling")
332 {
333   xbt_ex_t ex;
334   volatile int v1;
335   int c;
336
337   xbt_test_add("cleanup handling");
338
339   v1 = 1234;
340   c = 0;
341   TRY {
342     v1 = 5678;
343     THROWF(1, 2, "blah");
344   }
345   TRY_CLEANUP {
346     if (v1 != 5678)
347       xbt_test_fail("v1 = %d (!= 5678)", v1);
348     c = 1;
349   }
350   CATCH(ex) {
351     if (v1 != 5678)
352       xbt_test_fail("v1 = %d (!= 5678)", v1);
353     if (!(ex.category == 1 && ex.value == 2 && !strcmp(ex.msg, "blah")))
354       xbt_test_fail("unexpected exception contents");
355     xbt_ex_free(ex);
356   }
357   if (!c)
358     xbt_test_fail("xbt_ex_free not executed");
359 }
360
361
362 /*
363  * The following is the example included in the documentation. It's a good
364  * idea to check its syntax even if we don't try to run it.
365  * And actually, it allows to put comments in the code despite doxygen.
366  */
367 static char *mallocex(int size)
368 {
369   return NULL;
370 }
371
372 #define SMALLAMOUNT 10
373 #define TOOBIG 100000000
374
375 #if 0                           /* this contains syntax errors, actually */
376 static void bad_example(void)
377 {
378   struct {
379     char *first;
380   } *globalcontext;
381   ex_t ex;
382
383   /* BAD_EXAMPLE */
384   TRY {
385     char *cp1, *cp2, *cp3;
386
387     cp1 = mallocex(SMALLAMOUNT);
388     globalcontext->first = cp1;
389     cp2 = mallocex(TOOBIG);
390     cp3 = mallocex(SMALLAMOUNT);
391     strcpy(cp1, "foo");
392     strcpy(cp2, "bar");
393   }
394   TRY_CLEANUP {
395     free(cp3);
396     free(cp2);
397     free(cp1);
398   }
399   CATCH_ANONYMOUS {
400     printf("cp3=%s", cp3);
401     RETHROW;
402   }
403   /* end_of_bad_example */
404 }
405 #endif
406 typedef struct {
407   char *first;
408 } global_context_t;
409
410 static void good_example(void)
411 {
412   global_context_t *global_context = malloc(sizeof(global_context_t));
413
414   /* GOOD_EXAMPLE */
415   {                             /*01 */
416     char *volatile /*03 */ cp1 = NULL /*02 */ ;
417     char *volatile /*03 */ cp2 = NULL /*02 */ ;
418     char *volatile /*03 */ cp3 = NULL /*02 */ ;
419     TRY {
420       cp1 = mallocex(SMALLAMOUNT);
421       global_context->first = cp1;
422       cp1 = NULL /*05 give away */ ;
423       cp2 = mallocex(TOOBIG);
424       cp3 = mallocex(SMALLAMOUNT);
425       strcpy(cp1, "foo");
426       strcpy(cp2, "bar");
427     }
428     TRY_CLEANUP {               /*04 */
429       printf("cp3=%s", cp3 == NULL /*02 */ ? "" : cp3);
430       free(cp3);
431       free(cp2);
432       /*05 cp1 was given away */
433     }
434     CATCH_ANONYMOUS {
435       /*05 global context untouched */
436       RETHROW;
437     }
438   }
439   /* end_of_good_example */
440 }
441 #endif                          /* SIMGRID_TEST */