Logo AND Algorithmique Numérique Distribuée

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