Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
sed -i -e 's/\t/ /g' *.[ch] Please people, stop using tabs in your source
[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 XBT_EXPORT_NO_IMPORT(const xbt_running_ctx_t) __xbt_ex_ctx_initializer = XBT_RUNNING_CTX_INITIALIZER;
69
70 /* default __ex_ctx callback function */
71 xbt_running_ctx_t *__xbt_ex_ctx_default(void)
72 {
73   /* Don't scream: this is a default which is never used (so, yes,
74      there is one setjump container by running entity).
75
76      This default gets overriden in xbt/xbt_os_thread.c so that it works in
77      real life and in simulation when using threads to implement the simulation
78      processes (ie, with pthreads and on windows).
79
80      It also gets overriden in xbt/context.c when using ucontextes (as well as
81      in Java for now, but after the java overhaul, it will get cleaned out)
82    */
83   static xbt_running_ctx_t ctx = XBT_RUNNING_CTX_INITIALIZER;
84
85   return &ctx;
86 }
87
88 /* Change raw libc symbols to file names and line numbers */
89 void xbt_ex_setup_backtrace(xbt_ex_t * e);
90
91 void xbt_backtrace_display(xbt_ex_t * e)
92 {
93   xbt_ex_setup_backtrace(e);
94
95 #ifdef HAVE_BACKTRACE
96   if (e->used == 0) {
97     fprintf(stderr, "(backtrace not set)\n");
98   } else {
99     int i;
100
101     fprintf(stderr, "Backtrace (displayed in thread %p):\n",
102             (void *) xbt_thread_self());
103     for (i = 1; i < e->used; i++)       /* no need to display "xbt_backtrace_display" */
104       fprintf(stderr, "---> %s\n", e->bt_strings[i] + 4);
105   }
106
107   /* don't fool xbt_ex_free with uninitialized msg field */
108   e->msg = NULL;
109   e->remote = 0;
110   xbt_ex_free(*e);
111 #else
112
113   XBT_ERROR("No backtrace on this arch");
114 #endif
115 }
116
117 /** \brief show the backtrace of the current point (lovely while debuging) */
118 void xbt_backtrace_display_current(void)
119 {
120   xbt_ex_t e;
121   xbt_backtrace_current(&e);
122   xbt_backtrace_display(&e);
123 }
124
125 #if defined(HAVE_EXECINFO_H) && defined(HAVE_POPEN) && defined(ADDR2LINE)
126 # include "backtrace_linux.c"
127 #elif (defined(_XBT_WIN32) && defined (_M_IX86)) && !defined(__GNUC__)
128 # include "backtrace_windows.c"
129 #else
130 # include "backtrace_dummy.c"
131 #endif
132
133 /** @brief shows an exception content and the associated stack if available */
134 void xbt_ex_display(xbt_ex_t * e)
135 {
136   char *thrower = NULL;
137
138   if (e->remote)
139     thrower = bprintf(" on host %s(%d)", e->host, e->pid);
140
141   fprintf(stderr,
142           "** SimGrid: UNCAUGHT EXCEPTION received on %s(%d): category: %s; value: %d\n"
143           "** %s\n"
144           "** Thrown by %s()%s\n",
145           gras_os_myname(), xbt_getpid(),
146           xbt_ex_catname(e->category), e->value, e->msg,
147           e->procname, thrower ? thrower : " in this process");
148   XBT_CRITICAL("%s", e->msg);
149   xbt_free(thrower);
150
151   if (!e->remote && !e->bt_strings)
152     xbt_ex_setup_backtrace(e);
153
154 #ifdef HAVE_BACKTRACE
155   if (e->used && e->bt_strings) {
156     /* We have everything to build neat backtraces */
157     int i;
158
159     fprintf(stderr, "\n");
160     for (i = 0; i < e->used; i++)
161       fprintf(stderr, "%s\n", e->bt_strings[i]);
162
163   } else
164 #endif
165   {
166     fprintf(stderr,
167             "\n"
168             "**   In %s() at %s:%d\n"
169             "**   (no backtrace available)\n",
170             e->func, e->file, e->line);
171   }
172 }
173
174
175 /* default __ex_terminate callback function */
176 void __xbt_ex_terminate_default(xbt_ex_t * e)
177 {
178   xbt_ex_display(e);
179
180   abort();
181 }
182
183 /* the externally visible API */
184 XBT_EXPORT_NO_IMPORT(xbt_running_ctx_fetcher_t) __xbt_running_ctx_fetch = &__xbt_ex_ctx_default;
185 XBT_EXPORT_NO_IMPORT(ex_term_cb_t) __xbt_ex_terminate =
186     &__xbt_ex_terminate_default;
187
188
189 void xbt_ex_free(xbt_ex_t e)
190 {
191   int i;
192
193   free(e.msg);
194   if (e.remote) {
195     free(e.procname);
196     free(e.file);
197     free(e.func);
198     free(e.host);
199   }
200
201   if (e.bt_strings) {
202     for (i = 0; i < e.used; i++)
203       free(e.bt_strings[i]);
204     free(e.bt_strings);
205   }
206   /* memset(e,0,sizeof(xbt_ex_t)); */
207 }
208
209 /** \brief returns a short name for the given exception category */
210 const char *xbt_ex_catname(xbt_errcat_t cat)
211 {
212   switch (cat) {
213   case unknown_error:
214     return "unknown error";
215   case arg_error:
216     return "invalid argument";
217   case bound_error:
218     return "out of bounds";
219   case mismatch_error:
220     return "mismatch";
221   case not_found_error:
222     return "not found";
223   case system_error:
224     return "system error";
225   case network_error:
226     return "network error";
227   case timeout_error:
228     return "timeout";
229   case cancel_error:
230     return "action canceled";
231   case thread_error:
232     return "thread error";
233   case host_error:
234     return "host failed";
235   case tracing_error:
236     return "tracing error";
237   case io_error:
238     return "io error";
239   }
240   return "INVALID ERROR";
241 }
242
243
244 #ifdef SIMGRID_TEST
245 #include <stdio.h>
246 #include "xbt/ex.h"
247
248 XBT_TEST_SUITE("xbt_ex", "Exception Handling");
249
250 XBT_TEST_UNIT("controlflow", test_controlflow, "basic nested control flow")
251 {
252   xbt_ex_t ex;
253   volatile int n = 1;
254
255   xbt_test_add("basic nested control flow");
256
257   TRY {
258     if (n != 1)
259       xbt_test_fail("M1: n=%d (!= 1)", n);
260     n++;
261     TRY {
262       if (n != 2)
263         xbt_test_fail("M2: n=%d (!= 2)", n);
264       n++;
265       THROWF(unknown_error, 0, "something");
266     }
267     CATCH(ex) {
268       if (n != 3)
269         xbt_test_fail("M3: n=%d (!= 3)", n);
270       n++;
271       xbt_ex_free(ex);
272     }
273     n++;
274     TRY {
275       if (n != 5)
276         xbt_test_fail("M2: n=%d (!= 5)", n);
277       n++;
278       THROWF(unknown_error, 0, "something");
279     }
280     CATCH_ANONYMOUS {
281       if (n != 6)
282         xbt_test_fail("M3: n=%d (!= 6)", n);
283       n++;
284       RETHROW;
285       n++;
286     }
287     xbt_test_fail("MX: n=%d (shouldn't reach this point)", n);
288   }
289   CATCH(ex) {
290     if (n != 7)
291       xbt_test_fail("M4: n=%d (!= 7)", n);
292     n++;
293     xbt_ex_free(ex);
294   }
295   if (n != 8)
296     xbt_test_fail("M5: n=%d (!= 8)", n);
297 }
298
299 XBT_TEST_UNIT("value", test_value, "exception value passing")
300 {
301   xbt_ex_t ex;
302
303   TRY {
304     THROWF(unknown_error, 2, "toto");
305   }
306   CATCH(ex) {
307     xbt_test_add("exception value passing");
308     if (ex.category != unknown_error)
309       xbt_test_fail("category=%d (!= 1)", (int)ex.category);
310     if (ex.value != 2)
311       xbt_test_fail("value=%d (!= 2)", ex.value);
312     if (strcmp(ex.msg, "toto"))
313       xbt_test_fail("message=%s (!= toto)", ex.msg);
314     xbt_ex_free(ex);
315   }
316 }
317
318 XBT_TEST_UNIT("variables", test_variables, "variable value preservation")
319 {
320   xbt_ex_t ex;
321   int r1;
322   int _XBT_GNUC_UNUSED r2;
323   volatile int v1, v2;
324
325   r1 = r2 = v1 = v2 = 1234;
326   TRY {
327     r2 = 5678;
328     v2 = 5678;
329     THROWF(unknown_error, 0, "toto");
330   }
331   CATCH(ex) {
332     xbt_test_add("variable preservation");
333     if (r1 != 1234)
334       xbt_test_fail("r1=%d (!= 1234)", r1);
335     if (v1 != 1234)
336       xbt_test_fail("v1=%d (!= 1234)", v1);
337     /* r2 is allowed to be destroyed because not volatile */
338     if (v2 != 5678)
339       xbt_test_fail("v2=%d (!= 5678)", v2);
340     xbt_ex_free(ex);
341   }
342 }
343
344 XBT_TEST_UNIT("cleanup", test_cleanup, "cleanup handling")
345 {
346   xbt_ex_t ex;
347   volatile int v1;
348   int c;
349
350   xbt_test_add("cleanup handling");
351
352   v1 = 1234;
353   c = 0;
354   TRY {
355     v1 = 5678;
356     THROWF(1, 2, "blah");
357   }
358   TRY_CLEANUP {
359     if (v1 != 5678)
360       xbt_test_fail("v1 = %d (!= 5678)", v1);
361     c = 1;
362   }
363   CATCH(ex) {
364     if (v1 != 5678)
365       xbt_test_fail("v1 = %d (!= 5678)", v1);
366     if (!(ex.category == 1 && ex.value == 2 && !strcmp(ex.msg, "blah")))
367       xbt_test_fail("unexpected exception contents");
368     xbt_ex_free(ex);
369   }
370   if (!c)
371     xbt_test_fail("xbt_ex_free not executed");
372 }
373
374
375 /*
376  * The following is the example included in the documentation. It's a good
377  * idea to check its syntax even if we don't try to run it.
378  * And actually, it allows to put comments in the code despite doxygen.
379  */
380 static char *mallocex(int size)
381 {
382   return NULL;
383 }
384
385 #define SMALLAMOUNT 10
386 #define TOOBIG 100000000
387
388 #if 0                           /* this contains syntax errors, actually */
389 static void bad_example(void)
390 {
391   struct {
392     char *first;
393   } *globalcontext;
394   ex_t ex;
395
396   /* BAD_EXAMPLE */
397   TRY {
398     char *cp1, *cp2, *cp3;
399
400     cp1 = mallocex(SMALLAMOUNT);
401     globalcontext->first = cp1;
402     cp2 = mallocex(TOOBIG);
403     cp3 = mallocex(SMALLAMOUNT);
404     strcpy(cp1, "foo");
405     strcpy(cp2, "bar");
406   }
407   TRY_CLEANUP {
408     free(cp3);
409     free(cp2);
410     free(cp1);
411   }
412   CATCH_ANONYMOUS {
413     printf("cp3=%s", cp3);
414     RETHROW;
415   }
416   /* end_of_bad_example */
417 }
418 #endif
419 typedef struct {
420   char *first;
421 } global_context_t;
422
423 static void good_example(void)
424 {
425   global_context_t *global_context = malloc(sizeof(global_context_t));
426
427   /* GOOD_EXAMPLE */
428   {                             /*01 */
429     char *volatile /*03 */ cp1 = NULL /*02 */ ;
430     char *volatile /*03 */ cp2 = NULL /*02 */ ;
431     char *volatile /*03 */ cp3 = NULL /*02 */ ;
432     TRY {
433       cp1 = mallocex(SMALLAMOUNT);
434       global_context->first = cp1;
435       cp1 = NULL /*05 give away */ ;
436       cp2 = mallocex(TOOBIG);
437       cp3 = mallocex(SMALLAMOUNT);
438       strcpy(cp1, "foo");
439       strcpy(cp2, "bar");
440     }
441     TRY_CLEANUP {               /*04 */
442       printf("cp3=%s", cp3 == NULL /*02 */ ? "" : cp3);
443       free(cp3);
444       free(cp2);
445       /*05 cp1 was given away */
446     }
447     CATCH_ANONYMOUS {
448       /*05 global context untouched */
449       RETHROW;
450     }
451   }
452   /* end_of_good_example */
453 }
454 #endif                          /* SIMGRID_TEST */