summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYann Ylavic <ylavic@apache.org>2022-01-19 23:47:34 +0000
committerYann Ylavic <ylavic@apache.org>2022-01-19 23:47:34 +0000
commit2584f4b466d9e06983c9c3a474e52a74543b1ece (patch)
tree8fe791862d9e7ee45e8453eb83829bb83c12dfb3
parentc7cbb3818838b618d525c2639c41d02cce08a28a (diff)
downloadapr-2584f4b466d9e06983c9c3a474e52a74543b1ece.tar.gz
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
-rw-r--r--include/apr_thread_proc.h37
-rw-r--r--threadproc/beos/thread.c85
-rw-r--r--threadproc/netware/thread.c104
-rw-r--r--threadproc/os2/thread.c84
-rw-r--r--threadproc/unix/thread.c88
-rw-r--r--threadproc/win32/thread.c91
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,9 +209,28 @@ 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.
* @param cont The pool to use
@@ -270,6 +289,24 @@ APR_DECLARE(apr_status_t) apr_thread_create(apr_thread_t **new_thread,
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
* @param retval The return value to pass back to any thread that cares
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);
}