Index: ossp-pkg/ex/ex.pod RCS File: /v/ossp/cvs/ossp-pkg/ex/ex.pod,v rcsdiff -q -kk '-r1.12' '-r1.13' -u '/v/ossp/cvs/ossp-pkg/ex/ex.pod,v' 2>/dev/null --- ex.pod 2002/01/30 11:55:52 1.12 +++ ex.pod 2002/01/30 12:17:58 1.13 @@ -328,117 +328,122 @@ =head2 GNU pth -Using B with B is straight-forward. One just have to -wrap pth_init() and pth_spawn() to tie the exception facility to the -threading facility. +Using B with B is straight-forward, because B +already has support for B built-in. All which is needed is that +B is configured with the Autoconf option C<--with-ex>. Then +each thread has its own B exception context. + +=head2 POSIX pthreads + +Using B inside a standard B environment is +also straight-forward, although it requires additional coding. What +you basically have to do is to make sure that the B<__ex_ctx> becomes +a per-thread context and that B<__ex_terminate> terminates only the +current thread. To get an impression, a small utility library for this +follows: =over 4 -=item F +=item F - #ifndef __PTH_EX_H__ - #define __PTH_EX_H__ - - #include "pth.h" - - 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 - - #include - - #define PTH_EX_INTERNAL - #include "pth_ex.h" - #include "pth.h" - #include "ex.h" - - /* context storage key */ - static pth_key_t pth_ex_ctx_key; - - /* context destructor */ - 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(); - - /* 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(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_spawn_ex_t wrapper; - - /* spawn thread but execute start function through wrapper */ - wrapper.entry = entry; - wrapper.arg = arg; - return pth_spawn(attr, pth_spawn_wrapper, &wrapper); - } +#ifndef __PTHREAD_EX_H__ +#define __PTHREAD_EX_H__ -=back +#include -=head2 POSIX pthreads +int pthread_init_ex (void); +int pthread_create_ex (pthread_t *thread, const pthread_attr_t *attr, void *(*entry)(void *), void *arg); + +#ifndef PTHREAD_EX_INTERNAL +#define pthread_init pthread_init_ex +#define pthread_create pthread_create_ex +#endif + +#endif /* __PTHREAD_EX_H__ */ + +=item F + +#include +#include + +#define PTHREAD_EX_INTERNAL +#include "pthread_ex.h" +#include "ex.h" + +/* context storage key */ +static pthread_key_t pthread_ex_ctx_key; + +/* context destructor */ +static void pthread_ex_ctx_destroy(void *data) +{ + if (data != NULL) + free(data); + return; +} + +/* callback: context fetching */ +static ex_ctx_t *pthread_ex_ctx(void) +{ + return (ex_ctx_t *)pthread_getspecific(pthread_ex_ctx_key); +} + +/* callback: termination */ +static void pthread_ex_terminate(ex_t *e) +{ + pthread_exit(e->ex_value); +} + +/* pthread init */ +int pthread_init_ex(void) +{ + int rc; + + /* additionally create thread data key and override OSSP ex callbacks */ + pthread_key_create(&pthread_ex_ctx_key, pthread_ex_ctx_destroy); + __ex_ctx = pthread_ex_ctx; + __ex_terminate = pthread_ex_terminate; + + return rc; +} + +/* internal thread entry wrapper information */ +typedef struct { + void *(*entry)(void *); + void *arg; +} pthread_create_ex_t; + +/* internal thread entry wrapper */ +static void *pthread_create_wrapper(void *arg) +{ + pthread_create_ex_t *wrapper; + ex_ctx_t *ex_ctx; + + /* create per-thread exception context */ + wrapper = (pthread_create_ex_t *)arg; + ex_ctx = (ex_ctx_t *)malloc(sizeof(ex_ctx_t)); + EX_CTX_INITIALIZE(ex_ctx); + pthread_setspecific(pthread_ex_ctx_key, ex_ctx); + + /* perform original operation */ + return wrapper->entry(wrapper->arg); +} + +/* pthread_create() wrapper */ +int pthread_create_ex(pthread_t *thread, const pthread_attr_t *attr, void *(*entry)(void *), void *arg) +{ + pthread_create_ex_t wrapper; + + /* spawn thread but execute start function through wrapper */ + wrapper.entry = entry; + wrapper.arg = arg; + return pthread_create(thread, attr, pthread_create_wrapper, &wrapper); +} + +=back -Using B inside a B environment is identical to -using it inside B. You can use the same solution as above by -just replacing all B prefixes with B prefixes. +Now all which is required is that you include F after +the standard F header and to call B() once at +startup of your program. =head1 EXAMPLES