Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Fix copyright headers
[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(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 ex_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 ex_ctx_t ctx = XBT_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_display_backtrace" */
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   ERROR0("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(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   CRITICAL1("%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     fprintf(stderr, "\n");
157     for (i = 0; i < e->used; i++)
158       fprintf(stderr, "%s\n", e->bt_strings[i]);
159
160   }
161 #else
162   fprintf(stderr, " at %s:%d:%s (no backtrace available on that arch)\n",
163           e->file, e->line, e->func);
164 #endif
165 }
166
167
168 /* default __ex_terminate callback function */
169 void __xbt_ex_terminate_default(xbt_ex_t * e)
170 {
171   xbt_ex_display(e);
172
173   abort();
174 }
175
176 /* the externally visible API */
177 XBT_EXPORT_NO_IMPORT(ex_ctx_cb_t) __xbt_ex_ctx = &__xbt_ex_ctx_default;
178 XBT_EXPORT_NO_IMPORT(ex_term_cb_t) __xbt_ex_terminate =
179   &__xbt_ex_terminate_default;
180
181
182      void xbt_ex_free(xbt_ex_t e)
183 {
184   int i;
185
186   if (e.msg)
187     free(e.msg);
188   if (e.remote) {
189     free(e.procname);
190     free(e.file);
191     free(e.func);
192     free(e.host);
193   }
194
195   if (e.bt_strings) {
196     for (i = 0; i < e.used; i++)
197       free((char *) e.bt_strings[i]);
198     free((char **) e.bt_strings);
199   }
200   /* memset(e,0,sizeof(xbt_ex_t)); */
201 }
202
203 /** \brief returns a short name for the given exception category */
204 const char *xbt_ex_catname(xbt_errcat_t cat)
205 {
206   switch (cat) {
207   case unknown_error:
208     return "unknown_err";
209   case arg_error:
210     return "invalid_arg";
211   case mismatch_error:
212     return "mismatch";
213   case not_found_error:
214     return "not found";
215   case system_error:
216     return "system_err";
217   case network_error:
218     return "network_err";
219   case timeout_error:
220     return "timeout";
221   case thread_error:
222     return "thread_err";
223   default:
224     return "INVALID_ERR";
225   }
226 }
227
228
229 #ifdef SIMGRID_TEST
230 #include <stdio.h>
231 #include "xbt/ex.h"
232
233 XBT_TEST_SUITE("xbt_ex", "Exception Handling");
234
235 XBT_TEST_UNIT("controlflow", test_controlflow, "basic nested control flow")
236 {
237   xbt_ex_t ex;
238   volatile int n = 1;
239
240   xbt_test_add0("basic nested control flow");
241
242   TRY {
243     if (n != 1)
244       xbt_test_fail1("M1: n=%d (!= 1)", n);
245     n++;
246     TRY {
247       if (n != 2)
248         xbt_test_fail1("M2: n=%d (!= 2)", n);
249       n++;
250       THROW0(unknown_error, 0, "something");
251     }
252     CATCH(ex) {
253       if (n != 3)
254         xbt_test_fail1("M3: n=%d (!= 3)", n);
255       n++;
256       xbt_ex_free(ex);
257     }
258     n++;
259     TRY {
260       if (n != 5)
261         xbt_test_fail1("M2: n=%d (!= 5)", n);
262       n++;
263       THROW0(unknown_error, 0, "something");
264     }
265     CATCH(ex) {
266       if (n != 6)
267         xbt_test_fail1("M3: n=%d (!= 6)", n);
268       n++;
269       RETHROW;
270       n++;
271     }
272     xbt_test_fail1("MX: n=%d (shouldn't reach this point)", n);
273   }
274   CATCH(ex) {
275     if (n != 7)
276       xbt_test_fail1("M4: n=%d (!= 7)", n);
277     n++;
278     xbt_ex_free(ex);
279   }
280   if (n != 8)
281     xbt_test_fail1("M5: n=%d (!= 8)", n);
282 }
283
284 XBT_TEST_UNIT("value", test_value, "exception value passing")
285 {
286   xbt_ex_t ex;
287
288   TRY {
289     THROW0(unknown_error, 2, "toto");
290   }
291   CATCH(ex) {
292     xbt_test_add0("exception value passing");
293     if (ex.category != unknown_error)
294       xbt_test_fail1("category=%d (!= 1)", ex.category);
295     if (ex.value != 2)
296       xbt_test_fail1("value=%d (!= 2)", ex.value);
297     if (strcmp(ex.msg, "toto"))
298       xbt_test_fail1("message=%s (!= toto)", ex.msg);
299     xbt_ex_free(ex);
300   }
301 }
302
303 XBT_TEST_UNIT("variables", test_variables, "variable value preservation")
304 {
305   xbt_ex_t ex;
306   int r1, r2;
307   volatile int v1, v2;
308
309   r1 = r2 = v1 = v2 = 1234;
310   TRY {
311     r2 = 5678;
312     v2 = 5678;
313     THROW0(unknown_error, 0, "toto");
314   } CATCH(ex) {
315     xbt_test_add0("variable preservation");
316     if (r1 != 1234)
317       xbt_test_fail1("r1=%d (!= 1234)", r1);
318     if (v1 != 1234)
319       xbt_test_fail1("v1=%d (!= 1234)", v1);
320     /* r2 is allowed to be destroyed because not volatile */
321     if (v2 != 5678)
322       xbt_test_fail1("v2=%d (!= 5678)", v2);
323     xbt_ex_free(ex);
324   }
325 }
326
327 XBT_TEST_UNIT("cleanup", test_cleanup, "cleanup handling")
328 {
329   xbt_ex_t ex;
330   volatile int v1;
331   int c;
332
333   xbt_test_add0("cleanup handling");
334
335   v1 = 1234;
336   c = 0;
337   TRY {
338     v1 = 5678;
339     THROW0(1, 2, "blah");
340   } CLEANUP {
341     if (v1 != 5678)
342       xbt_test_fail1("v1 = %d (!= 5678)", v1);
343     c = 1;
344   }
345   CATCH(ex) {
346     if (v1 != 5678)
347       xbt_test_fail1("v1 = %d (!= 5678)", v1);
348     if (!(ex.category == 1 && ex.value == 2 && !strcmp(ex.msg, "blah")))
349       xbt_test_fail0("unexpected exception contents");
350     xbt_ex_free(ex);
351   }
352   if (!c)
353     xbt_test_fail0("xbt_ex_free not executed");
354 }
355
356
357 /*
358  * The following is the example included in the documentation. It's a good
359  * idea to check its syntax even if we don't try to run it.
360  * And actually, it allows to put comments in the code despite doxygen.
361  */
362 static char *mallocex(int size)
363 {
364   return NULL;
365 }
366
367 #define SMALLAMOUNT 10
368 #define TOOBIG 100000000
369
370 #if 0                           /* this contains syntax errors, actually */
371 static void bad_example(void)
372 {
373   struct {
374     char *first;
375   } *globalcontext;
376   ex_t ex;
377
378   /* BAD_EXAMPLE */
379   TRY {
380     char *cp1, *cp2, *cp3;
381
382     cp1 = mallocex(SMALLAMOUNT);
383     globalcontext->first = cp1;
384     cp2 = mallocex(TOOBIG);
385     cp3 = mallocex(SMALLAMOUNT);
386     strcpy(cp1, "foo");
387     strcpy(cp2, "bar");
388   } CLEANUP {
389     if (cp3 != NULL)
390       free(cp3);
391     if (cp2 != NULL)
392       free(cp2);
393     if (cp1 != NULL)
394       free(cp1);
395   }
396   CATCH(ex) {
397     printf("cp3=%s", cp3);
398     RETHROW;
399   }
400   /* end_of_bad_example */
401 }
402 #endif
403 typedef struct {
404   char *first;
405 } global_context_t;
406
407 static void good_example(void)
408 {
409   global_context_t *global_context = malloc(sizeof(global_context_t));
410   xbt_ex_t ex;
411
412   /* GOOD_EXAMPLE */
413   {                             /*01 */
414     char *volatile /*03 */ cp1 = NULL /*02 */ ;
415     char *volatile /*03 */ cp2 = NULL /*02 */ ;
416     char *volatile /*03 */ cp3 = NULL /*02 */ ;
417     TRY {
418       cp1 = mallocex(SMALLAMOUNT);
419       global_context->first = cp1;
420       cp1 = NULL /*05 give away */ ;
421       cp2 = mallocex(TOOBIG);
422       cp3 = mallocex(SMALLAMOUNT);
423       strcpy(cp1, "foo");
424       strcpy(cp2, "bar");
425     } CLEANUP {                 /*04 */
426       printf("cp3=%s", cp3 == NULL /*02 */ ? "" : cp3);
427       if (cp3 != NULL)
428         free(cp3);
429       if (cp2 != NULL)
430         free(cp2);
431       /*05 cp1 was given away */
432     }
433     CATCH(ex) {
434       /*05 global context untouched */
435       RETHROW;
436     }
437   }
438   /* end_of_good_example */
439 }
440 #endif /* SIMGRID_TEST */