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
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
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
00375 nxs_exception_declare(NXSRootException);
00381 nxs_exception_declare(NXSAssertionFailureException);
00387 nxs_exception_declare(NXSMemoryAllocationException);
00393
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
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
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