nxs_exception.h

00001 
00021 #ifndef NXS_HEADERS_EXCEPTION
00022 #define NXS_HEADERS_EXCEPTION
00023 
00024 #ifdef HAVE_CONFIG_H
00025 #include "config.h"
00026 #endif
00027 
00028 #include <assert.h>
00029 #include <setjmp.h>
00030 #include <stdbool.h>
00031 #include <stddef.h>
00032 #include <stdlib.h>
00033 
00034 #ifndef NXS_EXCEPTION_THREAD_UNSAFE
00035 #include "nxs_thread.h"
00036 #ifndef NXS_THREAD_HAS_TLS
00037 #define NXS_EXCEPTION_THREAD_UNSAFE
00038 #endif
00039 #endif
00040 
00041 /* TYPES */
00048 typedef struct nxs_exception_type {
00050     const struct nxs_exception_type * const parent;
00051     
00053     const char * const                      name;
00054 } nxs_exception_type;
00055 
00057 union nxs_exception_data {
00059     const void *                    readonly;
00060     
00062           void *                    writable;
00063 };
00064 
00070 typedef struct nxs_exception {
00071     const struct nxs_exception *        _backtrace;
00072     
00074     const struct nxs_exception_type *   type;
00075     
00077     const char *                        func;
00078     
00080     unsigned long                       line;
00081     
00083     union nxs_exception_data            data;
00084 } nxs_exception;
00085 
00086 /* MACROS */
00093 #define nxs_exception_declare(_type) \
00094     extern const struct nxs_exception_type         _type ## _;              \
00095     extern const struct nxs_exception_type * const _type
00096 
00103 #define nxs_exception_define(_parent, _type) \
00104         nxs_exception_define_(&_parent ## _, _type)
00105 
00112 #define nxs_exception_define_root(_type) \
00113         nxs_exception_define_(NULL, _type)
00114 
00120 #define nxs_exception_assert(_cond) \
00121         nxs_exception_assert_(_cond)
00122 
00130 #define nxs_raise(_type, _data) \
00131         nxs_raise_(_type, _data, __func__, __LINE__)
00132 
00138 #define nxs_rethrow(_exception) \
00139     do {                                                                    \
00140         const struct nxs_exception *_nxs_orig = (_exception);               \
00141         struct nxs_exception _nxs_new =                                     \
00142             {                                                               \
00143                 ._backtrace = _nxs_orig,                                    \
00144                 .type = _nxs_orig->type,                                    \
00145                 .data = _nxs_orig->data                                     \
00146             };                                                              \
00147         nxs_throw(&_nxs_new);                                               \
00148     } while (0)
00149 
00155 #define nxs_throw(_exception) \
00156     do {                                                                    \
00157         struct nxs_exception _nxs_ex = *(_exception);                       \
00158         _nxs_ex.func = __func__;                                            \
00159         _nxs_ex.line = __LINE__;                                            \
00160         nxs_throw_(&_nxs_ex);                                               \
00161     } while (0)
00162 
00181 #define nxs_try \
00182     struct nxs_exception_data_ *_nxs_current_data =                         \
00183         nxs_exception_block_push();                                         \
00184                                                                             \
00185     volatile int _nxs_setjmpResult = setjmp(_nxs_current_data->context);    \
00186     for (bool _nxs_brokeOut = true, _nxs_a = (_nxs_setjmpResult == 0);      \
00187          _nxs_a;_nxs_a = false, _nxs_brokeOut &&                            \
00188             (nxs_exception_block_pop() , _nxs_setjmpResult = 2))            \
00189         for (;_nxs_a;_nxs_a = false, _nxs_brokeOut = false)
00190 
00221 #define nxs_always \
00222     for (bool _nxs_b = true;_nxs_b;_nxs_b = false)
00223 
00259 #define nxs_catch(_type, _var) \
00260     for (;_nxs_setjmpResult == 1 && (_type == NULL ||                       \
00261             nxs_exception_is(&_nxs_current_data->exception, _type));        \
00262             nxs_exception_block_pop(), _nxs_setjmpResult = 0)               \
00263         for (_var = &_nxs_current_data->exception;                          \
00264              _nxs_setjmpResult == 1;_nxs_setjmpResult = 0)
00265 
00300 #define nxs_catch_any(_var) \
00301         nxs_catch(NULL, _var)
00302 
00335 #define nxs_catch_only(_type, _var) \
00336     bool _nxs_only_fail;                                                    \
00337     if (_nxs_setjmpResult == 1) {                                           \
00338         if (_type == NULL ||                                                \
00339             !nxs_exception_is(&_nxs_current_data->exception, _type))        \
00340         {                                                                   \
00341             nxs_exception_block_pop();                                      \
00342             nxs_rethrow(&_nxs_current_data->exception);                     \
00343         } else                                                              \
00344             _nxs_only_fail = false;                                         \
00345     } else                                                                  \
00346             _nxs_only_fail = true;                                          \
00347                                                                             \
00348     for (;!_nxs_only_fail;nxs_exception_block_pop(),                        \
00349          _nxs_only_fail = true, nxs_setjmpResult = 0)                       \
00350         for (_var = &_nxs_current_data->exception;                          \
00351              !_nxs_only_fail;_nxs_only_fail = true)
00352 
00366 #define nxs_end \
00367     do {                                                                    \
00368         if (_nxs_setjmpResult == 1) {                                       \
00369             nxs_exception_block_pop();                                      \
00370             nxs_rethrow(&_nxs_current_data->exception);                     \
00371         }                                                                   \
00372     } while (0)
00373 
00374 /* EXCEPTIONS */
00375 nxs_exception_declare(NXSRootException);
00381 nxs_exception_declare(NXSAssertionFailureException);
00387 nxs_exception_declare(NXSMemoryAllocationException);
00393 /* PUBLIC FUNCTION PROTOTYPES */
00401 bool                    nxs_exception_init          (void);
00402 
00412 void                    nxs_exception_cleanup       (void);
00413 
00418 bool                    nxs_exception_is            (const struct nxs_exception *exception, const struct nxs_exception_type *type);
00419 
00424 static inline
00425 void                    nxs_exception_print_trace   (const struct nxs_exception *exception);
00426 
00428 /* IMPLEMENTATION DETAILS BELOW */
00429 #define nxs_exception_define_(_parent, _name) \
00430     const struct nxs_exception_type _name ## _       =                      \
00431         { .parent = _parent, .name = #_name };                              \
00432     const struct nxs_exception_type * const _name    = &(_name ## _)
00433 
00434 #ifdef NDEBUG
00435 #define nxs_exception_assert_(_cond) ((void)0)
00436 #else
00437 #define nxs_exception_assert_(_cond) \
00438     do {                                                                    \
00439         if (!(_cond))                                                       \
00440             nxs_raise(NXSAssertionFailureException, NULL);                  \
00441     } while (0)
00442 #endif
00443 
00444 typedef struct nxs_exception_data_ {
00445     struct nxs_exception_data_ *    parent;
00446     jmp_buf                         context;
00447     struct nxs_exception            exception;
00448 } nxs_exception_data_;
00449 
00450 #ifdef NXS_EXCEPTION_THREAD_UNSAFE
00451 extern struct nxs_exception_data_ * nxs_exception_currentBlock;
00452 #else
00453 extern nxs_thread_tls               nxs_exception_currentBlockTLS;
00454 #endif
00455 
00456 static inline
00457 void                    nxs_exception_block_pop     (void);
00458 
00459 static inline
00460 nxs_exception_data_ *   nxs_exception_block_push    (void);
00461 
00462 void                    nxs_exception_print_trace_  (const struct nxs_exception *exception, bool uncaught);
00463 
00464 static inline
00465 void                    nxs_raise_                  (const struct nxs_exception_type *type, const void *data, const char *func, unsigned long int line);
00466 
00467 void                    nxs_throw_                  (const struct nxs_exception *exception);
00468 
00469 /* INLINE FUNCTION DEFINITIONS */
00470 static inline
00471 void                    nxs_exception_block_pop     (void) {
00472 #ifdef NXS_EXCEPTION_THREAD_UNSAFE
00473     struct nxs_exception_data_ *currentBlock = nxs_exception_currentBlock;
00474 #else
00475     struct nxs_exception_data_ *currentBlock =
00476         nxs_thread_tls_get(nxs_exception_currentBlockTLS);
00477 #endif
00478 
00479     assert(currentBlock != NULL);
00480 
00481 #ifdef NXS_EXCEPTION_THREAD_UNSAFE
00482     nxs_exception_currentBlock = currentBlock->parent;
00483 #else
00484     bool blockWasPopped =
00485         nxs_thread_tls_set(nxs_exception_currentBlockTLS, currentBlock);
00486     
00487     assert(blockWasPopped);
00488 #endif
00489 
00490     free(currentBlock);
00491 }
00492 
00493 static inline
00494 nxs_exception_data_ *   nxs_exception_block_push    (void) {
00495     struct nxs_exception_data_ *ret = malloc(sizeof(*ret));
00496 
00497     if (ret == NULL)
00498         nxs_raise(NXSMemoryAllocationException, NULL);
00499 
00500 #ifdef NXS_EXCEPTION_THREAD_UNSAFE
00501     ret->parent = nxs_exception_currentBlock;
00502     nxs_exception_currentBlock = ret;
00503 #else
00504     ret->parent = nxs_thread_tls_get(nxs_exception_currentBlockTLS);
00505     bool blockWasPushed =
00506         nxs_thread_tls_set(nxs_exception_currentBlockTLS, ret);
00507     
00508     assert(blockWasPushed);
00509 #endif
00510 
00511     return ret;
00512 }
00513 
00514 static inline
00515 void                    nxs_exception_print_trace   (const struct nxs_exception *exception) {
00516     nxs_exception_print_trace_(exception, false);
00517 }
00518 
00519 static inline
00520 void                    nxs_raise_                  (const struct nxs_exception_type *type, const void *data, const char *func, unsigned long int line) {
00521     assert(type != NULL);
00522 
00523     struct nxs_exception ex =
00524         { .type = type, .func = func, .line = line, .data.readonly = data };
00525     
00526     nxs_throw_(&ex);
00527 }
00528 
00529 #endif

Generated on Thu Dec 20 13:42:46 2007 for NXS Toolkit by  doxygen 1.5.4