From b156be5476d0023476fee17f618b3b11cea5aefe Mon Sep 17 00:00:00 2001 From: ylavic Date: Wed, 19 Jan 2022 23:47:34 +0000 Subject: apr_thread: Use compiler's TLS to track the current apr_thread_t's pointer. All modern compilers provide a Thread Local Storage keyword that allows to store per-thread data efficiently (C++11 's thread_local, C11's _Thread_local, gcc/clang's __thread or MSVC's __declspec(thread)). Use that to have an apr_thread_t pointer associated with each thread created by apr_thread_create() or any native thread (like the process' initial thread) that registered itself with the new apr_thread_current_create() function. This mechanism allows to implement apr_thread_current() quite efficiently, if available, otherwise the function returns NULL. If available APR_HAS_THREAD_LOCAL is #define'd to 1 and the APR_THREAD_LOCAL macro is the keyword usable to register TLS variables natively. Both APR_HAS_THREAD_LOCAL and APR_THREAD_LOCAL are #undef'ined if the compiler does not provide the mechanism. This allows to test for the functionality at compile time. When APR_HAS_THREAD_LOCAL, the user can load his/her own TLS data with: apr_thread_data_get(&my_data, my_key, apr_thread_current()); and store them with: apr_thread_data_set(my_data, my_key, my_data_cleanup, apr_thread_current()); which can be nice to avoid the proliferation of native TLS keys. Merge r1897207 from trunk: Submitted by: ylavic git-svn-id: https://svn.apache.org/repos/asf/apr/apr/branches/1.8.x@1897223 13f79535-47bb-0310-9956-ffa450edef68 --- include/apr_thread_proc.h | 37 ++++++++++++++++ threadproc/beos/thread.c | 85 +++++++++++++++++++++++++++++++++--- threadproc/netware/thread.c | 104 ++++++++++++++++++++++++++++++++++---------- threadproc/os2/thread.c | 84 ++++++++++++++++++++++++++++++++--- threadproc/unix/thread.c | 88 +++++++++++++++++++++++++++++++++---- threadproc/win32/thread.c | 91 ++++++++++++++++++++++++++++++++++---- 6 files changed, 434 insertions(+), 55 deletions(-) diff --git a/include/apr_thread_proc.h b/include/apr_thread_proc.h index ea3c43f90..20169ed4d 100644 --- a/include/apr_thread_proc.h +++ b/include/apr_thread_proc.h @@ -209,8 +209,27 @@ typedef enum { /* Thread Function definitions */ +#undef APR_HAS_THREAD_LOCAL + #if APR_HAS_THREADS +/** + * APR_THREAD_LOCAL keyword mapping the compiler's. + */ +#if defined(__cplusplus) && __cplusplus >= 201103L +#define APR_THREAD_LOCAL thread_local +#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112 +#define APR_THREAD_LOCAL _Thread_local +#elif defined(__GNUC__) /* works for clang too */ +#define APR_THREAD_LOCAL __thread +#elif defined(WIN32) && defined(_MSC_VER) +#define APR_THREAD_LOCAL __declspec(thread) +#endif + +#ifdef APR_THREAD_LOCAL +#define APR_HAS_THREAD_LOCAL 1 +#endif + /** * Create and initialize a new threadattr variable * @param new_attr The newly created threadattr. @@ -269,6 +288,24 @@ APR_DECLARE(apr_status_t) apr_thread_create(apr_thread_t **new_thread, apr_thread_start_t func, void *data, apr_pool_t *cont); +/** + * Setup the current os_thread as an apr_thread + * @param current The current apr_thread set up (or reused) + * @param attr The threadattr associated with the current thread + * @param pool The parent pool of the current thread + * @return APR_SUCCESS, APR_EEXIST if the current thread is already set, + * any error otherwise + */ +APR_DECLARE(apr_status_t) apr_thread_current_create(apr_thread_t **current, + apr_threadattr_t *attr, + apr_pool_t *pool); +/** + * Get the current thread + * @param The current apr_thread, NULL if it is not an apr_thread or if + * it could not be determined. + */ +APR_DECLARE(apr_thread_t *) apr_thread_current(void); + /** * stop the current thread * @param thd The thread to stop diff --git a/threadproc/beos/thread.c b/threadproc/beos/thread.c index 880bba2b6..c65b5e23a 100644 --- a/threadproc/beos/thread.c +++ b/threadproc/beos/thread.c @@ -62,31 +62,43 @@ APR_DECLARE(apr_status_t) apr_threadattr_guardsize_set(apr_threadattr_t *attr, return APR_ENOTIMPL; } +#ifdef APR_HAS_THREAD_LOCAL +static APR_THREAD_LOCAL apr_thread_t *current_thread; +#endif + static void *dummy_worker(void *opaque) { apr_thread_t *thd = (apr_thread_t*)opaque; void *ret; +#ifdef APR_HAS_THREAD_LOCAL + current_thread = thd; +#endif + ret = thd->func(thd, thd->data); if (thd->detached) { apr_pool_destroy(thd->pool); } + +#ifdef APR_HAS_THREAD_LOCAL + current_thread = NULL; +#endif return ret; } -APR_DECLARE(apr_status_t) apr_thread_create(apr_thread_t **new, apr_threadattr_t *attr, - apr_thread_start_t func, void *data, - apr_pool_t *pool) +static apr_status_t alloc_thread(apr_thread_t **new, + apr_threadattr_t *attr, + apr_thread_start_t func, void *data, + apr_pool_t *pool) { - int32 temp; apr_status_t stat; apr_allocator_t *allocator; apr_pool_t *p; - + /* The thread can be detached anytime (from the creation or later with * apr_thread_detach), so it needs its own pool and allocator to not * depend on a parent pool which could be destroyed before the thread - * exits. The allocator needs no mutex obviously since the pool should + * exits. The allocator needs no mutex obviously since the pool should * not be used nor create children pools outside the thread. */ stat = apr_allocator_create(&allocator); @@ -113,6 +125,22 @@ APR_DECLARE(apr_status_t) apr_thread_create(apr_thread_t **new, apr_threadattr_t (*new)->exitval = -1; (*new)->detached = (attr && apr_threadattr_detach_get(attr) == APR_DETACH); + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_create(apr_thread_t **new, + apr_threadattr_t *attr, + apr_thread_start_t func, void *data, + apr_pool_t *pool) +{ + int32 temp; + apr_status_t stat; + + stat = alloc_thread(new, attr, func, data, pool); + if (stat != APR_SUCCESS) { + return stat; + } + if (attr) temp = attr->attr; else @@ -125,13 +153,46 @@ APR_DECLARE(apr_status_t) apr_thread_create(apr_thread_t **new, apr_threadattr_t /* Now we try to run it...*/ if (resume_thread((*new)->td) != B_NO_ERROR) { stat = errno; - apr_pool_destroy(p); + apr_pool_destroy((*new)->pool); return stat; } return APR_SUCCESS; } +APR_DECLARE(apr_status_t) apr_thread_current_create(apr_thread_t **current, + apr_threadattr_t *attr, + apr_pool_t *pool) +{ + apr_status_t stat; + + *current = apr_thread_current(); + if (*current) { + return APR_EEXIST; + } + + stat = alloc_thread(current, attr, NULL, NULL, pool); + if (stat != APR_SUCCESS) { + return stat; + } + + (*current)->td = apr_os_thread_current(); + +#ifdef APR_HAS_THREAD_LOCAL + current_thread = *current; +#endif + return APR_SUCCESS; +} + +APR_DECLARE(apr_thread_t *) apr_thread_current(void) +{ +#ifdef APR_HAS_THREAD_LOCAL + return current_thread; +#else + return NULL; +#endif +} + APR_DECLARE(apr_os_thread_t) apr_os_thread_current(void) { return find_thread(NULL); @@ -148,6 +209,9 @@ APR_DECLARE(apr_status_t) apr_thread_exit(apr_thread_t *thd, apr_status_t retval if (thd->detached) { apr_pool_destroy(thd->pool); } +#ifdef APR_HAS_THREAD_LOCAL + current_thread = NULL; +#endif exit_thread ((status_t)(retval)); /* This will never be reached... */ return APR_SUCCESS; @@ -198,6 +262,10 @@ void apr_thread_yield() APR_DECLARE(apr_status_t) apr_thread_data_get(void **data, const char *key, apr_thread_t *thread) { + if (thread == NULL) { + *data = NULL; + return APR_ENOTHREAD; + } return apr_pool_userdata_get(data, key, thread->pool); } @@ -205,6 +273,9 @@ APR_DECLARE(apr_status_t) apr_thread_data_set(void *data, const char *key, apr_status_t (*cleanup) (void *), apr_thread_t *thread) { + if (thread == NULL) { + return APR_ENOTHREAD; + } return apr_pool_userdata_set(data, key, cleanup, thread->pool); } diff --git a/threadproc/netware/thread.c b/threadproc/netware/thread.c index f86281980..698704476 100644 --- a/threadproc/netware/thread.c +++ b/threadproc/netware/thread.c @@ -64,34 +64,43 @@ APR_DECLARE(apr_status_t) apr_threadattr_guardsize_set(apr_threadattr_t *attr, return APR_ENOTIMPL; } +#ifdef APR_HAS_THREAD_LOCAL +static APR_THREAD_LOCAL apr_thread_t *current_thread; +#endif + static void *dummy_worker(void *opaque) { apr_thread_t *thd = (apr_thread_t *)opaque; void *ret; +#ifdef APR_HAS_THREAD_LOCAL + current_thread = thd; +#endif + ret = thd->func(thd, thd->data); if (thd->detached) { apr_pool_destroy(thd->pool); } + +#ifdef APR_HAS_THREAD_LOCAL + current_thread = NULL; +#endif return ret; } -apr_status_t apr_thread_create(apr_thread_t **new, - apr_threadattr_t *attr, - apr_thread_start_t func, - void *data, - apr_pool_t *pool) +static apr_status_t alloc_thread(apr_thread_t **new, + apr_threadattr_t *attr, + apr_thread_start_t func, void *data, + apr_pool_t *pool) { apr_status_t stat; - unsigned long flags = NX_THR_BIND_CONTEXT; - size_t stack_size = APR_DEFAULT_STACK_SIZE; apr_allocator_t *allocator; apr_pool_t *p; - + /* The thread can be detached anytime (from the creation or later with * apr_thread_detach), so it needs its own pool and allocator to not * depend on a parent pool which could be destroyed before the thread - * exits. The allocator needs no mutex obviously since the pool should + * exits. The allocator needs no mutex obviously since the pool should * not be used nor create children pools outside the thread. */ stat = apr_allocator_create(&allocator); @@ -130,6 +139,24 @@ apr_status_t apr_thread_create(apr_thread_t **new, return APR_ENOMEM; } + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_create(apr_thread_t **new, + apr_threadattr_t *attr, + apr_thread_start_t func, + void *data, + apr_pool_t *pool) +{ + apr_status_t stat; + unsigned long flags = NX_THR_BIND_CONTEXT; + size_t stack_size = APR_DEFAULT_STACK_SIZE; + + stat = alloc_thread(new, attr, func, data, pool); + if (stat != APR_SUCCESS) { + return stat; + } + /* An original stack size of 0 will allow NXCreateThread() to * assign a default system stack size. An original stack * size of less than 0 will assign the APR default stack size. @@ -138,11 +165,11 @@ apr_status_t apr_thread_create(apr_thread_t **new, if (attr && (attr->stack_size >= 0)) { stack_size = attr->stack_size; } - + if (attr && attr->detach) { flags |= NX_THR_DETACHED; } - + (*new)->ctx = NXContextAlloc( /* void(*start_routine)(void *arg) */ (void (*)(void *)) dummy_worker, /* void *arg */ (*new), @@ -161,13 +188,46 @@ apr_status_t apr_thread_create(apr_thread_t **new, /* NXThreadId_t *thread_id */ &(*new)->td); if (stat) { - apr_pool_destroy(p); + apr_pool_destroy((*new)->pool); return stat; } - + return APR_SUCCESS; } +APR_DECLARE(apr_status_t) apr_thread_current_create(apr_thread_t **current, + apr_threadattr_t *attr, + apr_pool_t *pool) +{ + apr_status_t stat; + + *current = apr_thread_current(); + if (*current) { + return APR_EEXIST; + } + + stat = alloc_thread(current, attr, NULL, NULL, pool); + if (stat != APR_SUCCESS) { + return stat; + } + + (*current)->td = apr_os_thread_current(); + +#ifdef APR_HAS_THREAD_LOCAL + current_thread = *current; +#endif + return APR_SUCCESS; +} + +APR_DECLARE(apr_thread_t *) apr_thread_current(void) +{ +#ifdef APR_HAS_THREAD_LOCAL + return current_thread; +#else + return NULL; +#endif +} + apr_os_thread_t apr_os_thread_current() { return NXThreadGetId(); @@ -190,6 +250,9 @@ apr_status_t apr_thread_exit(apr_thread_t *thd, if (thd->detached) { apr_pool_destroy(thd->pool); } +#ifdef APR_HAS_THREAD_LOCAL + current_thread = NULL; +#endif NXThreadExit(NULL); return APR_SUCCESS; } @@ -228,26 +291,21 @@ apr_status_t apr_thread_detach(apr_thread_t *thd) apr_status_t apr_thread_data_get(void **data, const char *key, apr_thread_t *thread) { - if (thread != NULL) { - return apr_pool_userdata_get(data, key, thread->pool); - } - else { - data = NULL; + if (thread == NULL) { + *data = NULL; return APR_ENOTHREAD; } + return apr_pool_userdata_get(data, key, thread->pool); } apr_status_t apr_thread_data_set(void *data, const char *key, apr_status_t (*cleanup) (void *), apr_thread_t *thread) { - if (thread != NULL) { - return apr_pool_userdata_set(data, key, cleanup, thread->pool); - } - else { - data = NULL; + if (thread == NULL) { return APR_ENOTHREAD; } + return apr_pool_userdata_set(data, key, cleanup, thread->pool); } APR_DECLARE(apr_status_t) apr_os_thread_get(apr_os_thread_t **thethd, diff --git a/threadproc/os2/thread.c b/threadproc/os2/thread.c index ff896a43b..694497683 100644 --- a/threadproc/os2/thread.c +++ b/threadproc/os2/thread.c @@ -68,29 +68,42 @@ APR_DECLARE(apr_status_t) apr_threadattr_guardsize_set(apr_threadattr_t *attr, return APR_ENOTIMPL; } +#ifdef APR_HAS_THREAD_LOCAL +static APR_THREAD_LOCAL apr_thread_t *current_thread; +#endif + static void dummy_worker(void *opaque) { +#ifdef APR_HAS_THREAD_LOCAL + current_thread = thread; +#endif + apr_thread_t *thread = (apr_thread_t *)opaque; thread->exitval = thread->func(thread, thread->data); if (thd->attr->attr & APR_THREADATTR_DETACHED) { apr_pool_destroy(thread->pool); } + +#ifdef APR_HAS_THREAD_LOCAL + current_thread = NULL; +#endif } -APR_DECLARE(apr_status_t) apr_thread_create(apr_thread_t **new, apr_threadattr_t *attr, - apr_thread_start_t func, void *data, - apr_pool_t *pool) +static apr_status_t alloc_thread(apr_thread_t **new, + apr_threadattr_t *attr, + apr_thread_start_t func, void *data, + apr_pool_t *pool) { apr_status_t stat; apr_allocator_t *allocator; apr_pool_t *p; - + /* The thread can be detached anytime (from the creation or later with * apr_thread_detach), so it needs its own pool and allocator to not * depend on a parent pool which could be destroyed before the thread - * exits. The allocator needs no mutex obviously since the pool should + * exits. The allocator needs no mutex obviously since the pool should * not be used nor create children pools outside the thread. */ stat = apr_allocator_create(&allocator); @@ -123,19 +136,66 @@ APR_DECLARE(apr_status_t) apr_thread_create(apr_thread_t **new, apr_threadattr_t } (*new)->attr = attr; - (*new)->tid = _beginthread(dummy_worker, NULL, + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_create(apr_thread_t **new, + apr_threadattr_t *attr, + apr_thread_start_t func, void *data, + apr_pool_t *pool) +{ + apr_status_t stat; + + stat = alloc_thread(new, attr, func, data, pool); + if (stat != APR_SUCCESS) { + return stat; + } + + (*new)->tid = _beginthread(dummy_worker, NULL, (*new)->attr->stacksize > 0 ? (*new)->attr->stacksize : APR_THREAD_STACKSIZE, (*new)); if ((*new)->tid < 0) { stat = errno; - apr_pool_destroy(p); + apr_pool_destroy((*new)->pool); return stat; } return APR_SUCCESS; } +APR_DECLARE(apr_status_t) apr_thread_current_create(apr_thread_t **current, + apr_threadattr_t *attr, + apr_pool_t *pool) +{ + apr_status_t stat; + + *current = apr_thread_current(); + if (*current) { + return APR_EEXIST; + } + + stat = alloc_thread(new, attr, NULL, NULL, pool); + if (stat != APR_SUCCESS) { + return stat; + } + + (*current)->tid = apr_os_thread_current(); + +#ifdef APR_HAS_THREAD_LOCAL + current_thread = *current; +#endif + return APR_SUCCESS; +} + +APR_DECLARE(apr_thread_t *) apr_thread_current(void) +{ +#ifdef APR_HAS_THREAD_LOCAL + return current_thread; +#else + return NULL; +#endif +} APR_DECLARE(apr_os_thread_t) apr_os_thread_current() @@ -154,6 +214,9 @@ APR_DECLARE(apr_status_t) apr_thread_exit(apr_thread_t *thd, apr_status_t retval if (thd->attr->attr & APR_THREADATTR_DETACHED) { apr_pool_destroy(thd->pool); } +#ifdef APR_HAS_THREAD_LOCAL + current_thread = NULL; +#endif _endthread(); return -1; /* If we get here something's wrong */ } @@ -232,6 +295,10 @@ int apr_os_thread_equal(apr_os_thread_t tid1, apr_os_thread_t tid2) APR_DECLARE(apr_status_t) apr_thread_data_get(void **data, const char *key, apr_thread_t *thread) { + if (thread == NULL) { + *data = NULL; + return APR_ENOTHREAD; + } return apr_pool_userdata_get(data, key, thread->pool); } @@ -241,6 +308,9 @@ APR_DECLARE(apr_status_t) apr_thread_data_set(void *data, const char *key, apr_status_t (*cleanup) (void *), apr_thread_t *thread) { + if (thread == NULL) { + return APR_ENOTHREAD; + } return apr_pool_userdata_set(data, key, cleanup, thread->pool); } diff --git a/threadproc/unix/thread.c b/threadproc/unix/thread.c index d8c0509fe..bb1db1e80 100644 --- a/threadproc/unix/thread.c +++ b/threadproc/unix/thread.c @@ -136,33 +136,43 @@ APR_DECLARE(apr_status_t) apr_threadattr_guardsize_set(apr_threadattr_t *attr, #endif } +#ifdef APR_HAS_THREAD_LOCAL +static APR_THREAD_LOCAL apr_thread_t *current_thread; +#endif + static void *dummy_worker(void *opaque) { apr_thread_t *thread = (apr_thread_t*)opaque; void *ret; +#ifdef APR_HAS_THREAD_LOCAL + current_thread = thread; +#endif + ret = thread->func(thread, thread->data); if (thread->detached) { apr_pool_destroy(thread->pool); } + +#ifdef APR_HAS_THREAD_LOCAL + current_thread = NULL; +#endif return ret; } -APR_DECLARE(apr_status_t) apr_thread_create(apr_thread_t **new, - apr_threadattr_t *attr, - apr_thread_start_t func, - void *data, - apr_pool_t *pool) +static apr_status_t alloc_thread(apr_thread_t **new, + apr_threadattr_t *attr, + apr_thread_start_t func, void *data, + apr_pool_t *pool) { apr_status_t stat; - pthread_attr_t *temp; apr_allocator_t *allocator; apr_pool_t *p; - + /* The thread can be detached anytime (from the creation or later with * apr_thread_detach), so it needs its own pool and allocator to not * depend on a parent pool which could be destroyed before the thread - * exits. The allocator needs no mutex obviously since the pool should + * exits. The allocator needs no mutex obviously since the pool should * not be used nor create children pools outside the thread. */ stat = apr_allocator_create(&allocator); @@ -193,6 +203,23 @@ APR_DECLARE(apr_status_t) apr_thread_create(apr_thread_t **new, return APR_ENOMEM; } + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_create(apr_thread_t **new, + apr_threadattr_t *attr, + apr_thread_start_t func, + void *data, + apr_pool_t *pool) +{ + apr_status_t stat; + pthread_attr_t *temp; + + stat = alloc_thread(new, attr, func, data, pool); + if (stat != APR_SUCCESS) { + return stat; + } + if (attr) temp = &attr->attr; else @@ -202,13 +229,46 @@ APR_DECLARE(apr_status_t) apr_thread_create(apr_thread_t **new, #ifdef HAVE_ZOS_PTHREADS stat = errno; #endif - apr_pool_destroy(p); + apr_pool_destroy((*new)->pool); + return stat; + } + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_current_create(apr_thread_t **current, + apr_threadattr_t *attr, + apr_pool_t *pool) +{ + apr_status_t stat; + + *current = apr_thread_current(); + if (*current) { + return APR_EEXIST; + } + + stat = alloc_thread(current, attr, NULL, NULL, pool); + if (stat != APR_SUCCESS) { return stat; } + *(*current)->td = apr_os_thread_current(); + +#ifdef APR_HAS_THREAD_LOCAL + current_thread = *current; +#endif return APR_SUCCESS; } +APR_DECLARE(apr_thread_t *) apr_thread_current(void) +{ +#ifdef APR_HAS_THREAD_LOCAL + return current_thread; +#else + return NULL; +#endif +} + APR_DECLARE(apr_os_thread_t) apr_os_thread_current(void) { return pthread_self(); @@ -227,6 +287,9 @@ APR_DECLARE(apr_status_t) apr_thread_exit(apr_thread_t *thd, if (thd->detached) { apr_pool_destroy(thd->pool); } +#ifdef APR_HAS_THREAD_LOCAL + current_thread = NULL; +#endif pthread_exit(NULL); return APR_SUCCESS; } @@ -297,6 +360,10 @@ APR_DECLARE(void) apr_thread_yield(void) APR_DECLARE(apr_status_t) apr_thread_data_get(void **data, const char *key, apr_thread_t *thread) { + if (thread == NULL) { + *data = NULL; + return APR_ENOTHREAD; + } return apr_pool_userdata_get(data, key, thread->pool); } @@ -304,6 +371,9 @@ APR_DECLARE(apr_status_t) apr_thread_data_set(void *data, const char *key, apr_status_t (*cleanup)(void *), apr_thread_t *thread) { + if (thread == NULL) { + return APR_ENOTHREAD; + } return apr_pool_userdata_set(data, key, cleanup, thread->pool); } diff --git a/threadproc/win32/thread.c b/threadproc/win32/thread.c index 0dd26a53b..0ed485642 100644 --- a/threadproc/win32/thread.c +++ b/threadproc/win32/thread.c @@ -72,34 +72,44 @@ APR_DECLARE(apr_status_t) apr_threadattr_guardsize_set(apr_threadattr_t *attr, return APR_ENOTIMPL; } +#ifdef APR_HAS_THREAD_LOCAL +static APR_THREAD_LOCAL apr_thread_t *current_thread; +#endif + static void *dummy_worker(void *opaque) { apr_thread_t *thd = (apr_thread_t *)opaque; void *ret; +#ifdef APR_HAS_THREAD_LOCAL + current_thread = thd; +#endif + TlsSetValue(tls_apr_thread, thd->td); ret = thd->func(thd, thd->data); if (!thd->td) { /* detached? */ apr_pool_destroy(thd->pool); } + +#ifdef APR_HAS_THREAD_LOCAL + current_thread = NULL; +#endif return ret; } -APR_DECLARE(apr_status_t) apr_thread_create(apr_thread_t **new, - apr_threadattr_t *attr, - apr_thread_start_t func, - void *data, apr_pool_t *pool) +static apr_status_t alloc_thread(apr_thread_t **new, + apr_threadattr_t *attr, + apr_thread_start_t func, void *data, + apr_pool_t *pool) { apr_status_t stat; - unsigned temp; - HANDLE handle; apr_allocator_t *allocator; apr_pool_t *p; - + /* The thread can be detached anytime (from the creation or later with * apr_thread_detach), so it needs its own pool and allocator to not * depend on a parent pool which could be destroyed before the thread - * exits. The allocator needs no mutex obviously since the pool should + * exits. The allocator needs no mutex obviously since the pool should * not be used nor create children pools outside the thread. */ stat = apr_allocator_create(&allocator); @@ -124,6 +134,23 @@ APR_DECLARE(apr_status_t) apr_thread_create(apr_thread_t **new, (*new)->data = data; (*new)->func = func; + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_create(apr_thread_t **new, + apr_threadattr_t *attr, + apr_thread_start_t func, + void *data, apr_pool_t *pool) +{ + apr_status_t stat; + unsigned temp; + HANDLE handle; + + stat = alloc_thread(new, attr, func, data, pool); + if (stat != APR_SUCCESS) { + return stat; + } + /* Use 0 for default Thread Stack Size, because that will * default the stack to the same size as the calling thread. */ @@ -133,7 +160,7 @@ APR_DECLARE(apr_status_t) apr_thread_create(apr_thread_t **new, (unsigned int (APR_THREAD_FUNC *)(void *))dummy_worker, (*new), 0, &temp)) == 0) { stat = APR_FROM_OS_ERROR(_doserrno); - apr_pool_destroy(p); + apr_pool_destroy((*new)->pool); return stat; } #else @@ -146,6 +173,7 @@ APR_DECLARE(apr_status_t) apr_thread_create(apr_thread_t **new, return stat; } #endif + if (attr && attr->detach) { CloseHandle(handle); } @@ -156,6 +184,41 @@ APR_DECLARE(apr_status_t) apr_thread_create(apr_thread_t **new, return APR_SUCCESS; } +APR_DECLARE(apr_status_t) apr_thread_current_create(apr_thread_t **current, + apr_threadattr_t *attr, + apr_pool_t *pool) +{ + apr_status_t stat; + + *current = apr_thread_current(); + if (*current) { + return APR_EEXIST; + } + + stat = alloc_thread(current, attr, NULL, NULL, pool); + if (stat != APR_SUCCESS) { + return stat; + } + + if (!(attr && attr->detach)) { + (*new)->td = apr_os_thread_current(); + } + +#ifdef APR_HAS_THREAD_LOCAL + current_thread = *current; +#endif + return APR_SUCCESS; +} + +APR_DECLARE(apr_thread_t *) apr_thread_current(void) +{ +#ifdef APR_HAS_THREAD_LOCAL + return current_thread; +#else + return NULL; +#endif +} + APR_DECLARE(apr_status_t) apr_thread_exit(apr_thread_t *thd, apr_status_t retval) { @@ -164,6 +227,9 @@ APR_DECLARE(apr_status_t) apr_thread_exit(apr_thread_t *thd, if (!thd->td) { /* detached? */ apr_pool_destroy(thd->pool); } +#ifdef APR_HAS_THREAD_LOCAL + current_thread = NULL; +#endif #ifndef _WIN32_WCE _endthreadex(0); #else @@ -234,6 +300,10 @@ APR_DECLARE(void) apr_thread_yield() APR_DECLARE(apr_status_t) apr_thread_data_get(void **data, const char *key, apr_thread_t *thread) { + if (thread == NULL) { + *data = NULL; + return APR_ENOTHREAD; + } return apr_pool_userdata_get(data, key, thread->pool); } @@ -241,6 +311,9 @@ APR_DECLARE(apr_status_t) apr_thread_data_set(void *data, const char *key, apr_status_t (*cleanup) (void *), apr_thread_t *thread) { + if (thread == NULL) { + return APR_ENOTHREAD; + } return apr_pool_userdata_set(data, key, cleanup, thread->pool); } -- cgit v1.2.1