Index: ossp-pkg/ex/ex.c RCS File: /v/ossp/cvs/ossp-pkg/ex/ex.c,v rcsdiff -q -kk '-r1.3' '-r1.4' -u '/v/ossp/cvs/ossp-pkg/ex/ex.c,v' 2>/dev/null --- ex.c 2002/01/26 22:35:02 1.3 +++ ex.c 2002/01/29 11:05:21 1.4 @@ -28,7 +28,28 @@ ** ex.c: exception handling (compiler part) */ +#include +#include + #include "ex.h" -ex_ctx_t __ex_ctx_global; +static ex_ctx_t *ex_ctx_default(void) +{ + static ex_ctx_t ctx = EX_CTX_INITIALIZER; + + return &ctx; +} + +static void ex_terminate_default(ex_t *e) +{ + fprintf(stderr, + "**EX: UNCAUGHT EXCEPTION: " + "class=0x%lx object=0x%lx value=0x%lx [%s:%d@%s]\n", + (long)((e)->ex_class), (long)((e)->ex_object), (long)((e)->ex_value), + (e)->ex_file, (e)->ex_line, (e)->ex_func); + abort(); +} + +ex_ctx_cb_t __ex_ctx = &ex_ctx_default; +ex_term_cb_t __ex_terminate = &ex_terminate_default; Index: ossp-pkg/ex/ex.h RCS File: /v/ossp/cvs/ossp-pkg/ex/ex.h,v rcsdiff -q -kk '-r1.9' '-r1.10' -u '/v/ossp/cvs/ossp-pkg/ex/ex.h,v' 2>/dev/null --- ex.h 2002/01/27 19:38:49 1.9 +++ ex.h 2002/01/29 11:05:21 1.10 @@ -93,10 +93,10 @@ /* declare the context type (private) */ typedef struct { - __ex_mctx_t *ctx_mctx; /* permanent machine context of enclosing try/catch */ - int ctx_disabled; /* permanent flag whether exception handling is disabled */ - int ctx_caught; /* temporary flag whether exception was caught */ - volatile ex_t ctx_ex; /* temporary exception storage */ + __ex_mctx_t *ctx_mctx; /* permanent machine context of enclosing try/catch */ + int ctx_disabled; /* permanent flag whether exception handling is disabled */ + int ctx_caught; /* temporary flag whether exception was caught */ + volatile ex_t ctx_ex; /* temporary exception storage */ } ex_ctx_t; /* the static and dynamic initializers for a context structure */ @@ -116,33 +116,17 @@ } while (0) /* the exception context */ -#if defined(__EX_CTX_USE_STATIC__) -static ex_ctx_t __ex_ctx_global; -#define __ex_ctx (&__ex_ctx_global) -#elif defined(__EX_CTX_USE_GLOBAL__) || !defined(__EX_CTX_USE_CUSTOM__) -#define EX_CTX_GLOBAL ex_ctx_t __ex_ctx_global; -extern ex_ctx_t __ex_ctx_global; -#define __ex_ctx (&__ex_ctx_global) -#endif +typedef ex_ctx_t *(*ex_ctx_cb_t)(void); +extern ex_ctx_cb_t __ex_ctx; /* the termination handler */ -#if defined(__EX_TERMINATE_USE_NOOP__) -#define __ex_terminate(e) \ - /* noop */ -#elif defined(__EX_TERMINATE_USE_ABORT__) || !defined(__EX_CTX_USE_CUSTOM__) -#define __ex_terminate(e) \ - ( fprintf(stderr, \ - "**EX: UNCAUGHT EXCEPTION: " \ - "class=0x%lx object=0x%lx value=0x%lx [%s:%d@%s]\n", \ - (long)((e)->ex_class), (long)((e)->ex_object), (long)((e)->ex_value), \ - (e)->ex_file, (e)->ex_line, (e)->ex_func), \ - abort() ) -#endif +typedef void (*ex_term_cb_t)(ex_t *); +extern ex_term_cb_t __ex_terminate; /* the block for trying execution */ #define ex_try \ { \ - ex_ctx_t *__ex_ctx_ptr = __ex_ctx; \ + ex_ctx_t *__ex_ctx_ptr = __ex_ctx(); \ __ex_mctx_t *__ex_mctx_en; \ __ex_mctx_t __ex_mctx_me; \ __ex_mctx_en = __ex_ctx_ptr->ctx_mctx; \ @@ -162,41 +146,42 @@ } \ __ex_ctx_ptr->ctx_mctx = __ex_mctx_en; \ } \ - if ( !(__ex_ctx->ctx_caught) \ - || ((e) = __ex_ctx->ctx_ex, 0)) { \ + if ( !(__ex_ctx()->ctx_caught) \ + || ((e) = __ex_ctx()->ctx_ex, 0)) { \ } \ else /* the throwing of a new exception */ #define ex_throw(c,o,v) \ - (__ex_ctx->ctx_disabled ? 0 : \ - (__ex_ctx->ctx_ex.ex_class = (void *)(c), \ - __ex_ctx->ctx_ex.ex_object = (void *)(o), \ - __ex_ctx->ctx_ex.ex_value = (void *)(v), \ - __ex_ctx->ctx_ex.ex_file = __FILE__, \ - __ex_ctx->ctx_ex.ex_line = __LINE__, \ - __ex_ctx->ctx_ex.ex_func = __EX_FUNC__, \ - ( __ex_ctx->ctx_mctx == NULL \ - ? (__ex_terminate(&(__ex_ctx->ctx_ex)), -1) \ - : (__ex_mctx_restore(__ex_ctx->ctx_mctx), 1) ))) + (__ex_ctx()->ctx_disabled ? 0 : \ + (__ex_ctx()->ctx_ex.ex_class = (void *)(c), \ + __ex_ctx()->ctx_ex.ex_object = (void *)(o), \ + __ex_ctx()->ctx_ex.ex_value = (void *)(v), \ + __ex_ctx()->ctx_ex.ex_file = __FILE__, \ + __ex_ctx()->ctx_ex.ex_line = __LINE__, \ + __ex_ctx()->ctx_ex.ex_func = __EX_FUNC__, \ + ( __ex_ctx()->ctx_mctx == NULL \ + ? (__ex_terminate((ex_t *)&(__ex_ctx()->ctx_ex)), -1) \ + : (__ex_mctx_restore(__ex_ctx()->ctx_mctx), 1) ))) /* the re-throwing of an already caught exception */ #define ex_rethrow \ - (__ex_ctx->ctx_disabled ? 0 : \ - (__ex_ctx->ctx_mctx == NULL ? (__ex_terminate(&(__ex_ctx->ctx_ex)), -1) : \ - (__ex_mctx_restore(__ex_ctx->ctx_mctx), 1) )) + (__ex_ctx()->ctx_disabled ? 0 : \ + ( __ex_ctx()->ctx_mctx == NULL \ + ? (__ex_terminate((ex_t *)&(__ex_ctx()->ctx_ex)), -1) \ + : (__ex_mctx_restore(__ex_ctx()->ctx_mctx), 1) )) /* shield an operation from exception handling */ #define ex_shield \ - for (__ex_ctx->ctx_disabled = 1; \ - __ex_ctx->ctx_disabled == 1; \ - __ex_ctx->ctx_disabled = 0) + for (__ex_ctx()->ctx_disabled = 1; \ + __ex_ctx()->ctx_disabled == 1; \ + __ex_ctx()->ctx_disabled = 0) /* exception handling tests */ #define ex_catching \ - (__ex_ctx->ctx_mctx != NULL) + (__ex_ctx()->ctx_mctx != NULL) #define ex_shielding \ - (__ex_ctx->ctx_disabled) + (__ex_ctx()->ctx_disabled) /* optional namespace mapping */ #if defined(__EX_NS_USE_UCCXX__) Index: ossp-pkg/ex/ex.pod RCS File: /v/ossp/cvs/ossp-pkg/ex/ex.pod,v rcsdiff -q -kk '-r1.7' '-r1.8' -u '/v/ossp/cvs/ossp-pkg/ex/ex.pod,v' 2>/dev/null --- ex.pod 2002/01/26 22:43:54 1.7 +++ ex.pod 2002/01/29 11:05:21 1.8 @@ -258,22 +258,13 @@ =head2 Exception Context In order to maintain the exception catching stack and for passing the -exception between the throw point and the catch point, B uses -a global exception context macro B<__ex_ctx> holding a pointer to a -structure of type B. This is a private data structure and -should be treated as opaque by the user. - -By default (define C<__EX_CTX_USE_GLOBAL__> or as long as -C<__EX_CTX_USE_CUSTOM__> is not defined) this references a global -variable C<__ex_ctx_global>. This variable is either defined by the user -by placing the directive "C" macro somewhere outside of -any functions in the application or alternatively link the F -library to the application. - -Alternatively one can define C<__EX_CTX_USE_STATIC__> to get a static -declaration directly inside the header file (for small environments -where F is included once only) or define C<__EX_CTX_USE_CUSTOM__> -and provide an own macro definition for B<__ex_ctx>. +exception between the throw and the catch point, B uses a +global exception context, returned on-the-fly by the callback "ex_ctx_t +*(*B<__ex_ctx>)(void)". + +The default B<__ex_ctx> (as provided by F) returns a pointer to +a static B context. For use in multi-threading environments, +this should be overwritten with a per-thread context structure. To initialize an exception context structure there are two macros defined: B for static initialization and @@ -281,20 +272,17 @@ =head2 Termination Handler -In case there is an exception thrown which is not caught by -any B/B clauses, B calls the macro -B<__ex_terminate>(C). It receives a pointer to the exception +In case there is an exception thrown which is not caught by any +B/B clauses, B calls the callback "void +(*B<__ex_terminate>)(C)". It receives a pointer to the exception object which should have been thrown. -By default (define C<__EX_TERMINATE_USE_ABORT__> or as long as -C<__EX_TERMINATE_USE_CUSTOM__> is not defined) this prints a message of -the form "C<**EX: UNCAUGHT EXCEPTION: class=0xXXXXXXXX object=0xXXXXXXXX -value=0xXXXXXXX [file:123:func]>" to F and then calls abort(3) -in order to terminate the application. - -Alternatively one can define C<__EX_TERMINATE_USE_NOOP__> to ignore the -exception or or define C<__EX_TERMINATE_USE_CUSTOM__> and provide an own -macro definition for B<__ex_terminate>. +The default B<__ex_terminate> (as provided by F) this prints +a message of the form "C<**EX: UNCAUGHT EXCEPTION: class=0xXXXXXXXX +object=0xXXXXXXXX value=0xXXXXXXX [file:123:func]>" to F and +then calls abort(3) in order to terminate the application. For use in +multi-threading environments, this should be overwritten with a callback +function which terminates only the current thread. =head2 Namespace Mapping @@ -307,10 +295,10 @@ For this B optionally provides the ability to provide additional namespace mappings for those API macros. By default (define -C<__EX_NS_USE_CXX__> o or as long as C<__EX_CTX_USE_CUSTOM__> and -C<__cplusplus> is not defined) you can additional C++ style macros named -B, B, B and B. As an alternative you -can define C<__EX_NS_USE_UCCXX__> to get the same but with an (more +C<__EX_NS_USE_CXX__> or as long as C<__EX_NS_USE_CUSTOM__> and +C<__cplusplus> is not defined) you can additional C++ style macros +named B, B, B and B. As an alternative +you can define C<__EX_NS_USE_UCCXX__> to get the same but with an (more namespace safe) upper case first letter. =head1 MULTITHREADING ENVIRONMENTS @@ -337,83 +325,98 @@ #ifndef __PTH_EX_H__ #define __PTH_EX_H__ - - /* include GNU pth API */ + #include "pth.h" - /* configure and include OSSP ex API */ - #define __EX_CTX_USE_CUSTOM__ - #define __ex_ctx \ - (ex_ctx_t *)pth_getkey(ex_ctx_key) - #define __ex_terminate(e) \ - pth_exit(e->ex_value) - #include "ex.h" - - int pth_init_ex(void); - pth_t pth_spawn_ex(pth_attr_t attr, void *(*entry)(void *), void *arg); - - #ifndef PTH_EX_C + int pth_init_ex (void); + pth_t pth_spawn_ex (pth_attr_t attr, void *(*entry)(void *), void *arg); + + #ifndef PTH_EX_INTERNAL #define pth_init pth_ex_init #define pth_spawn pth_ex_spawn #endif - + #endif /* __PTH_EX_H__ */ =item F - #define PTH_EX_C + #include + + #define PTH_EX_INTERNAL #include "pth_ex.h" - + #include "pth.h" + #include "ex.h" + /* context storage key */ - static pth_key_t ex_ctx_key; - + static pth_key_t pth_ex_ctx_key; + /* context destructor */ - void ex_ctx_destroy(void *data) + static void pth_ex_ctx_destroy(void *data) { if (data != NULL) free(data); return; } - + + /* callback: context fetching */ + static ex_ctx_t *pth_ex_ctx(void) + { + return (ex_ctx_t *)pth_key_getdata(pth_ex_ctx_key); + } + + /* callback: termination */ + static void pth_ex_terminate(ex_t *e) + { + pth_exit(e->ex_value); + } + /* pth_init() wrapper */ int pth_init_ex(void) { int rc; - + + /* perform original operation */ rc = pth_init(); - pth_key_create(&ex_ctx_key, ex_ctx_destroy); + + /* additionally create thread data key and override OSSP ex callbacks */ + pth_key_create(&pth_ex_ctx_key, pth_ex_ctx_destroy); + __ex_ctx = pth_ex_ctx; + __ex_terminate = pth_ex_terminate; + return rc; } - + /* internal thread entry wrapper information */ typedef struct { void *(*entry)(void *); void *arg; } pth_spawn_ex_t; - + /* internal thread entry wrapper */ static void *pth_spawn_wrapper(void *arg) { pth_spawn_ex_t *wrapper; ex_ctx_t *ex_ctx; - + + /* create per-thread exception context */ wrapper = (pth_spawn_ex_t *)arg; ex_ctx = (ex_ctx_t *)malloc(sizeof(ex_ctx_t)); EX_CTX_INITIALIZE(ex_ctx); - pth_key_setdata(ex_ctx_key, ex_ctx); - return wrapper.entry(wrapper.arg); + pth_key_setdata(pth_ex_ctx_key, ex_ctx); + + /* perform original operation */ + return wrapper->entry(wrapper->arg); } - + /* pth_spawn() wrapper */ pth_t pth_spawn_ex(pth_attr_t attr, void *(*entry)(void *), void *arg) { - pth_t tid; pth_spawn_ex_t wrapper; - + + /* spawn thread but execute start function through wrapper */ wrapper.entry = entry; wrapper.arg = arg; - tid = pth_spawn(attr, pth_spawn_wrapper, &wrapper); - return tid; + return pth_spawn(attr, pth_spawn_wrapper, &wrapper); } =back