Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
51e3a928d2465c68aa044585b4b80297c0fcc0a2
[simgrid.git] / include / xbt / ex.h
1 /*
2 **  OSSP ex - Exception Handling (modified to fit into SimGrid)
3 **  Copyright (c) 2005 Martin Quinson.
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 **
8 **  This file is part of OSSP ex, an exception handling library
9 **  which can be found at http://www.ossp.org/pkg/lib/ex/.
10 **
11 **  Permission to use, copy, modify, and distribute this software for
12 **  any purpose with or without fee is hereby granted, provided that
13 **  the above copyright notice and this permission notice appear in all
14 **  copies.
15 **
16 **  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
17 **  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 **  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 **  IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
20 **  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 **  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 **  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 **  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 **  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 **  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26 **  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 **  SUCH DAMAGE.
28 **
29 **  ex.h: exception handling (pre-processor part)
30 */
31
32 #ifndef __SG_EX_H__
33 #define __SG_EX_H__
34
35 #include <xbt/misc.h>
36 #include <xbt/sysdep.h>
37
38 /* required ISO-C standard facilities */
39 #include <stdio.h>
40
41 /* the machine context */
42 #if defined(__EX_MCTX_MCSC__)
43 #include <ucontext.h>            /* POSIX.1 ucontext(3) */
44 #define __ex_mctx_struct         ucontext_t uc;
45 #define __ex_mctx_save(mctx)     (getcontext(&(mctx)->uc) == 0)
46 #define __ex_mctx_restored(mctx) /* noop */
47 #define __ex_mctx_restore(mctx)  (void)setcontext(&(mctx)->uc)
48
49 #elif defined(__EX_MCTX_SSJLJ__)
50 #include <setjmp.h>              /* POSIX.1 sigjmp_buf(3) */
51 #define __ex_mctx_struct         sigjmp_buf jb;
52 #define __ex_mctx_save(mctx)     (sigsetjmp((mctx)->jb, 1) == 0)
53 #define __ex_mctx_restored(mctx) /* noop */
54 #define __ex_mctx_restore(mctx)  (void)siglongjmp((mctx)->jb, 1)
55
56 #elif defined(__EX_MCTX_SJLJ__) || !defined(__EX_MCTX_CUSTOM__)
57 #include <setjmp.h>              /* ISO-C jmp_buf(3) */
58 #define __ex_mctx_struct         jmp_buf jb;
59 #define __ex_mctx_save(mctx)     (setjmp((mctx)->jb) == 0)
60 #define __ex_mctx_restored(mctx) /* noop */
61 #define __ex_mctx_restore(mctx)  (void)longjmp((mctx)->jb, 1)
62 #endif
63
64 /* declare the machine context type */
65 typedef struct { __ex_mctx_struct } __ex_mctx_t;
66
67 /** Content of an exception */
68 typedef struct {
69   char *msg;      /*< human readable message; to be freed */
70   int   code;     /*< category like HTTP (what went wrong) */
71   int   value;    /*< like errno (why did it went wrong) */
72   /* throw point */
73   char *host;     /*< NULL for localhost; hostname:port if remote */
74   char *procname; 
75   char *file;     /*< to be freed only for remote exceptions */
76   int   line;
77   char *func;     /*< to be freed only for remote exceptions */
78 } ex_t;
79
80 /* declare the context type (private) */
81 typedef struct {
82     __ex_mctx_t  *ctx_mctx;     /* permanent machine context of enclosing try/catch */
83     int           ctx_deferred; /* permanent flag whether exception is deferred */
84     int           ctx_deferring;/* permanent counter of exception deferring level */
85     int           ctx_defer;    /* temporary flag for exception deferring macro */
86     int           ctx_shielding;/* permanent counter of exception shielding level */
87     int           ctx_shield;   /* temporary flag for exception shielding macro */
88     int           ctx_caught;   /* temporary flag whether exception was caught */
89     volatile ex_t ctx_ex;       /* temporary exception storage */
90 } ex_ctx_t;
91
92 /* the static and dynamic initializers for a context structure */
93 #define SG_CTX_INITIALIZER \
94     { NULL, 0, 0, 0, 0, 0, 0, { /* content */ NULL, 0, 0, \
95                                 /*throw point*/ NULL, NULL, NULL, 0, NULL } }
96 #define SG_CTX_INITIALIZE(ctx) \
97     do { \
98         (ctx)->ctx_mctx        = NULL; \
99         (ctx)->ctx_deferred    = 0;    \
100         (ctx)->ctx_deferring   = 0;    \
101         (ctx)->ctx_defer       = 0;    \
102         (ctx)->ctx_shielding   = 0;    \
103         (ctx)->ctx_shield      = 0;    \
104         (ctx)->ctx_caught      = 0;    \
105         (ctx)->ctx_ex.msg      = NULL; \
106         (ctx)->ctx_ex.code     = 0;    \
107         (ctx)->ctx_ex.value    = 0;    \
108         (ctx)->ctx_ex.host     = NULL; \
109         (ctx)->ctx_ex.procname = NULL; \
110         (ctx)->ctx_ex.file     = NULL; \
111         (ctx)->ctx_ex.line     = 0;    \
112         (ctx)->ctx_ex.func     = NULL; \
113     } while (0)
114
115 /* the exception context */
116 typedef ex_ctx_t *(*ex_ctx_cb_t)(void);
117 extern ex_ctx_cb_t __xbt_ex_ctx;
118 extern ex_ctx_t *__xbt_ex_ctx_default(void);
119
120 /* the termination handler */
121 typedef void (*ex_term_cb_t)(ex_t *);
122 extern ex_term_cb_t __xbt_ex_terminate;
123 extern void __xbt_ex_terminate_default(ex_t *e);
124
125 /* the block for trying execution */
126 #define sg_try \
127     { \
128         ex_ctx_t *__xbt_ex_ctx_ptr = __xbt_ex_ctx(); \
129         int __ex_cleanup = 0; \
130         __ex_mctx_t *__ex_mctx_en; \
131         __ex_mctx_t __ex_mctx_me; \
132         __ex_mctx_en = __xbt_ex_ctx_ptr->ctx_mctx; \
133         __xbt_ex_ctx_ptr->ctx_mctx = &__ex_mctx_me; \
134         if (__ex_mctx_save(&__ex_mctx_me)) { \
135             if (1)
136
137 /* the optional(!) block for cleanup */
138 #define sg_cleanup \
139             else { \
140             } \
141             __xbt_ex_ctx_ptr->ctx_caught = 0; \
142         } \
143         else { \
144             __ex_mctx_restored(&__ex_mctx_me); \
145             __xbt_ex_ctx_ptr->ctx_caught = 1; \
146         } \
147         __xbt_ex_ctx_ptr->ctx_mctx = __ex_mctx_en; \
148         __ex_cleanup = 1; \
149         if (1) { \
150             if (1)
151
152 /* the block for catching an exception */
153 #define sg_catch(e) \
154             else { \
155             } \
156             if (!(__ex_cleanup)) \
157                 __xbt_ex_ctx_ptr->ctx_caught = 0; \
158         } \
159         else { \
160             if (!(__ex_cleanup)) { \
161                 __ex_mctx_restored(&__ex_mctx_me); \
162                 __xbt_ex_ctx_ptr->ctx_caught = 1; \
163             } \
164         } \
165         __xbt_ex_ctx_ptr->ctx_mctx = __ex_mctx_en; \
166     } \
167     if (   !(__xbt_ex_ctx()->ctx_caught) \
168         || ((e) = __xbt_ex_ctx()->ctx_ex, 0)) { \
169     } \
170     else
171
172 /* the throwing of a new exception */
173 #define sg_throw(c,v,m) \
174     ((   __xbt_ex_ctx()->ctx_shielding > 0 \
175       || (__xbt_ex_ctx()->ctx_deferring > 0 && __xbt_ex_ctx()->ctx_deferred == 1)) ? 0 : \
176      (__xbt_ex_ctx()->ctx_ex.msg      = bprintf(m), \
177       __xbt_ex_ctx()->ctx_ex.code     = (c), \
178       __xbt_ex_ctx()->ctx_ex.value    = (v), \
179       __xbt_ex_ctx()->ctx_ex.host     = (char*)NULL, \
180       __xbt_ex_ctx()->ctx_ex.procname = strdup(xbt_procname()), \
181       __xbt_ex_ctx()->ctx_ex.file     = (char*)__FILE__, \
182       __xbt_ex_ctx()->ctx_ex.line     = __LINE__, \
183       __xbt_ex_ctx()->ctx_ex.func     = (char*)_XBT_FUNCTION, \
184       __xbt_ex_ctx()->ctx_deferred     = 1, \
185       (__xbt_ex_ctx()->ctx_deferring > 0 ? 0 : \
186        (__xbt_ex_ctx()->ctx_mctx == NULL \
187         ? (__xbt_ex_terminate((ex_t *)&(__xbt_ex_ctx()->ctx_ex)), -1) \
188         : (__ex_mctx_restore(__xbt_ex_ctx()->ctx_mctx), 1) ))))
189
190 /* the re-throwing of an already caught exception */
191 #define sg_rethrow \
192     ((   __xbt_ex_ctx()->ctx_shielding > 0 \
193       || __xbt_ex_ctx()->ctx_deferring > 0) ? 0 : \
194       (  __xbt_ex_ctx()->ctx_mctx == NULL \
195        ? (__xbt_ex_terminate((ex_t *)&(__xbt_ex_ctx()->ctx_ex)), -1) \
196        : (__ex_mctx_restore(__xbt_ex_ctx()->ctx_mctx), 1) ))
197
198 /* shield an operation from exception handling */
199 #define sg_shield \
200     for (__xbt_ex_ctx()->ctx_shielding++, \
201          __xbt_ex_ctx()->ctx_shield =  1; \
202          __xbt_ex_ctx()->ctx_shield == 1; \
203          __xbt_ex_ctx()->ctx_shield =  0, \
204          __xbt_ex_ctx()->ctx_shielding--)
205
206 /* defer immediate exception handling */
207 #define sg_defer \
208     for (((__xbt_ex_ctx()->ctx_deferring)++ == 0 ? __xbt_ex_ctx()->ctx_deferred = 0 : 0), \
209          __xbt_ex_ctx()->ctx_defer =  1;  \
210          __xbt_ex_ctx()->ctx_defer == 1;  \
211          __xbt_ex_ctx()->ctx_defer =  0,  \
212          ((--(__xbt_ex_ctx()->ctx_deferring) == 0 && __xbt_ex_ctx()->ctx_deferred == 1) ? sg_rethrow : 0))
213
214 /* exception handling tests */
215 #define sg_catching \
216     (__xbt_ex_ctx()->ctx_mctx != NULL)
217 #define sg_shielding \
218     (__xbt_ex_ctx()->ctx_shielding > 0)
219 #define sg_deferring \
220     (__xbt_ex_ctx()->ctx_deferring > 0)
221
222 /* optional namespace mapping */
223 #if defined(__EX_NS_UCCXX__)
224 #define Try      sg_try
225 #define Cleanup  sg_cleanup
226 #define Catch    sg_catch
227 #define Throw    sg_throw
228 #define Rethrow  sg_rethrow
229 #define Shield   sg_shield
230 #define Defer    sg_defer
231 #elif defined(__EX_NS_CXX__) || (!defined(__cplusplus) && !defined(__EX_NS_CUSTOM__))
232 #define try      sg_try
233 #define cleanup  sg_cleanup
234 #define catch    sg_catch
235 #define throw    sg_throw
236 #define rethrow  sg_rethrow
237 #define shield   sg_shield
238 #define defer    sg_defer
239 #endif
240
241 #endif /* __SG_EX_H__ */
242