From 311e7361992caf835f22e90771fc203ef9d33f33 Mon Sep 17 00:00:00 2001 From: ivan Date: Wed, 9 Feb 2022 10:39:35 +0000 Subject: On 'win32-pollset-wakeup-no-file-socket-emulation' branch: Merge changes from trunk. git-svn-id: https://svn.apache.org/repos/asf/apr/apr/branches/win32-pollset-wakeup-no-file-socket-emulation@1897894 13f79535-47bb-0310-9956-ffa450edef68 --- include/apr_poll.h | 1 + include/apr_thread_proc.h | 49 ++++++++++++++++- poll/unix/epoll.c | 12 +++-- poll/unix/kqueue.c | 127 +++++++++++++++++++++++++++----------------- test/testbuckets.c | 8 +-- threadproc/beos/proc.c | 3 ++ threadproc/beos/thread.c | 93 ++++++++++++++++++++++++++++---- threadproc/netware/proc.c | 3 ++ threadproc/netware/thread.c | 114 ++++++++++++++++++++++++++++++--------- threadproc/os2/proc.c | 3 ++ threadproc/os2/thread.c | 91 +++++++++++++++++++++++++++---- threadproc/unix/proc.c | 3 ++ threadproc/unix/thread.c | 96 +++++++++++++++++++++++++++++---- threadproc/win32/thread.c | 102 +++++++++++++++++++++++++++++++---- 14 files changed, 581 insertions(+), 124 deletions(-) diff --git a/include/apr_poll.h b/include/apr_poll.h index 482d6ee1d..3cfbfc810 100644 --- a/include/apr_poll.h +++ b/include/apr_poll.h @@ -52,6 +52,7 @@ extern "C" { #define APR_POLLERR 0x010 /**< Pending error */ #define APR_POLLHUP 0x020 /**< Hangup occurred */ #define APR_POLLNVAL 0x040 /**< Descriptor invalid */ +#define APR_POLLEXCL 0x080 /**< Exclusive wake up */ /** @} */ /** diff --git a/include/apr_thread_proc.h b/include/apr_thread_proc.h index b1bd01533..85f697dd2 100644 --- a/include/apr_thread_proc.h +++ b/include/apr_thread_proc.h @@ -211,6 +211,25 @@ typedef enum { #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 +#else +#define APR_HAS_THREAD_LOCAL 0 +#endif + /** * Create and initialize a new threadattr variable * @param new_attr The newly created threadattr. @@ -269,6 +288,30 @@ 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 native 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); + +/** + * Clear the current thread after fork() + */ +APR_DECLARE(void) apr_thread_current_after_fork(void); + +/** + * 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 @@ -389,7 +432,11 @@ APR_DECLARE(apr_status_t) apr_threadkey_data_set(void *data, const char *key, apr_status_t (*cleanup) (void *), apr_threadkey_t *threadkey); -#endif +#else /* APR_HAS_THREADS */ + +#define APR_HAS_THREAD_LOCAL 0 + +#endif /* APR_HAS_THREADS */ /** * Create and initialize a new procattr variable diff --git a/poll/unix/epoll.c b/poll/unix/epoll.c index c00a1094d..7e811241d 100644 --- a/poll/unix/epoll.c +++ b/poll/unix/epoll.c @@ -25,9 +25,9 @@ #if defined(HAVE_EPOLL) -static apr_int16_t get_epoll_event(apr_int16_t event) +static unsigned get_epoll_event(apr_int16_t event) { - apr_int16_t rv = 0; + unsigned rv = 0; if (event & APR_POLLIN) rv |= EPOLLIN; @@ -35,12 +35,16 @@ static apr_int16_t get_epoll_event(apr_int16_t event) rv |= EPOLLPRI; if (event & APR_POLLOUT) rv |= EPOLLOUT; +#ifdef EPOLLEXCLUSIVE + if (event & APR_POLLEXCL) + rv |= EPOLLEXCLUSIVE; +#endif /* APR_POLLNVAL is not handled by epoll. EPOLLERR and EPOLLHUP are return-only */ return rv; } -static apr_int16_t get_epoll_revent(apr_int16_t event) +static apr_int16_t get_epoll_revent(unsigned event) { apr_int16_t rv = 0; @@ -123,7 +127,7 @@ static apr_status_t impl_pollset_create(apr_pollset_t *pollset, } #endif - pollset->p = apr_palloc(p, sizeof(apr_pollset_private_t)); + pollset->p = apr_pcalloc(p, sizeof(apr_pollset_private_t)); #if APR_HAS_THREADS if ((flags & APR_POLLSET_THREADSAFE) && !(flags & APR_POLLSET_NOCOPY) && diff --git a/poll/unix/kqueue.c b/poll/unix/kqueue.c index e8a1ef95b..aa4251f1b 100644 --- a/poll/unix/kqueue.c +++ b/poll/unix/kqueue.c @@ -75,9 +75,12 @@ static apr_status_t impl_pollset_create(apr_pollset_t *pollset, apr_uint32_t flags) { apr_status_t rv; - pollset->p = apr_palloc(p, sizeof(apr_pollset_private_t)); + + pollset->p = apr_pcalloc(p, sizeof(apr_pollset_private_t)); + #if APR_HAS_THREADS if (flags & APR_POLLSET_THREADSAFE && + !(flags & APR_POLLSET_NOCOPY) && ((rv = apr_thread_mutex_create(&pollset->p->ring_lock, APR_THREAD_MUTEX_DEFAULT, p)) != APR_SUCCESS)) { @@ -99,14 +102,9 @@ static apr_status_t impl_pollset_create(apr_pollset_t *pollset, * for the same descriptor) */ pollset->p->setsize = 2 * size; - - pollset->p->ke_set = - (struct kevent *) apr_palloc(p, pollset->p->setsize * sizeof(struct kevent)); - - memset(pollset->p->ke_set, 0, pollset->p->setsize * sizeof(struct kevent)); + pollset->p->ke_set = apr_pcalloc(p, pollset->p->setsize * sizeof(struct kevent)); pollset->p->kqueue_fd = kqueue(); - if (pollset->p->kqueue_fd == -1) { pollset->p = NULL; return apr_get_netos_error(); @@ -133,9 +131,11 @@ static apr_status_t impl_pollset_create(apr_pollset_t *pollset, pollset->p->result_set = apr_palloc(p, pollset->p->setsize * sizeof(apr_pollfd_t)); - APR_RING_INIT(&pollset->p->query_ring, pfd_elem_t, link); - APR_RING_INIT(&pollset->p->free_ring, pfd_elem_t, link); - APR_RING_INIT(&pollset->p->dead_ring, pfd_elem_t, link); + if (!(flags & APR_POLLSET_NOCOPY)) { + APR_RING_INIT(&pollset->p->query_ring, pfd_elem_t, link); + APR_RING_INIT(&pollset->p->free_ring, pfd_elem_t, link); + APR_RING_INIT(&pollset->p->dead_ring, pfd_elem_t, link); + } return APR_SUCCESS; } @@ -144,20 +144,22 @@ static apr_status_t impl_pollset_add(apr_pollset_t *pollset, const apr_pollfd_t *descriptor) { apr_os_sock_t fd; - pfd_elem_t *elem; + pfd_elem_t *elem = NULL; apr_status_t rv = APR_SUCCESS; - pollset_lock_rings(); + if (!(pollset->flags & APR_POLLSET_NOCOPY)) { + pollset_lock_rings(); - if (!APR_RING_EMPTY(&(pollset->p->free_ring), pfd_elem_t, link)) { - elem = APR_RING_FIRST(&(pollset->p->free_ring)); - APR_RING_REMOVE(elem, link); - } - else { - elem = (pfd_elem_t *) apr_palloc(pollset->pool, sizeof(pfd_elem_t)); - APR_RING_ELEM_INIT(elem, link); + if (!APR_RING_EMPTY(&(pollset->p->free_ring), pfd_elem_t, link)) { + elem = APR_RING_FIRST(&(pollset->p->free_ring)); + APR_RING_REMOVE(elem, link); + } + else { + elem = (pfd_elem_t *) apr_palloc(pollset->pool, sizeof(pfd_elem_t)); + APR_RING_ELEM_INIT(elem, link); + } + elem->pfd = *descriptor; } - elem->pfd = *descriptor; if (descriptor->desc_type == APR_POLL_SOCKET) { fd = descriptor->desc.s->socketdes; @@ -167,7 +169,14 @@ static apr_status_t impl_pollset_add(apr_pollset_t *pollset, } if (descriptor->reqevents & APR_POLLIN) { - EV_SET(&pollset->p->kevent, fd, EVFILT_READ, EV_ADD, 0, 0, elem); + if (pollset->flags & APR_POLLSET_NOCOPY) { + EV_SET(&pollset->p->kevent, fd, EVFILT_READ, EV_ADD, 0, 0, + descriptor); + } + else { + EV_SET(&pollset->p->kevent, fd, EVFILT_READ, EV_ADD, 0, 0, + elem); + } if (kevent(pollset->p->kqueue_fd, &pollset->p->kevent, 1, NULL, 0, NULL) == -1) { @@ -176,7 +185,14 @@ static apr_status_t impl_pollset_add(apr_pollset_t *pollset, } if (descriptor->reqevents & APR_POLLOUT && rv == APR_SUCCESS) { - EV_SET(&pollset->p->kevent, fd, EVFILT_WRITE, EV_ADD, 0, 0, elem); + if (pollset->flags & APR_POLLSET_NOCOPY) { + EV_SET(&pollset->p->kevent, fd, EVFILT_WRITE, EV_ADD, 0, 0, + descriptor); + } + else { + EV_SET(&pollset->p->kevent, fd, EVFILT_WRITE, EV_ADD, 0, 0, + elem); + } if (kevent(pollset->p->kqueue_fd, &pollset->p->kevent, 1, NULL, 0, NULL) == -1) { @@ -184,14 +200,16 @@ static apr_status_t impl_pollset_add(apr_pollset_t *pollset, } } - if (rv == APR_SUCCESS) { - APR_RING_INSERT_TAIL(&(pollset->p->query_ring), elem, pfd_elem_t, link); - } - else { - APR_RING_INSERT_TAIL(&(pollset->p->free_ring), elem, pfd_elem_t, link); - } + if (!(pollset->flags & APR_POLLSET_NOCOPY)) { + if (rv == APR_SUCCESS) { + APR_RING_INSERT_TAIL(&(pollset->p->query_ring), elem, pfd_elem_t, link); + } + else { + APR_RING_INSERT_TAIL(&(pollset->p->free_ring), elem, pfd_elem_t, link); + } - pollset_unlock_rings(); + pollset_unlock_rings(); + } return rv; } @@ -199,12 +217,9 @@ static apr_status_t impl_pollset_add(apr_pollset_t *pollset, static apr_status_t impl_pollset_remove(apr_pollset_t *pollset, const apr_pollfd_t *descriptor) { - pfd_elem_t *ep; apr_status_t rv; apr_os_sock_t fd; - pollset_lock_rings(); - if (descriptor->desc_type == APR_POLL_SOCKET) { fd = descriptor->desc.s->socketdes; } @@ -231,20 +246,26 @@ static apr_status_t impl_pollset_remove(apr_pollset_t *pollset, } } - for (ep = APR_RING_FIRST(&(pollset->p->query_ring)); - ep != APR_RING_SENTINEL(&(pollset->p->query_ring), - pfd_elem_t, link); - ep = APR_RING_NEXT(ep, link)) { + if (!(pollset->flags & APR_POLLSET_NOCOPY)) { + pfd_elem_t *ep; + + pollset_lock_rings(); - if (descriptor->desc.s == ep->pfd.desc.s) { - APR_RING_REMOVE(ep, link); - APR_RING_INSERT_TAIL(&(pollset->p->dead_ring), - ep, pfd_elem_t, link); - break; + for (ep = APR_RING_FIRST(&(pollset->p->query_ring)); + ep != APR_RING_SENTINEL(&(pollset->p->query_ring), + pfd_elem_t, link); + ep = APR_RING_NEXT(ep, link)) { + + if (descriptor->desc.s == ep->pfd.desc.s) { + APR_RING_REMOVE(ep, link); + APR_RING_INSERT_TAIL(&(pollset->p->dead_ring), + ep, pfd_elem_t, link); + break; + } } - } - pollset_unlock_rings(); + pollset_unlock_rings(); + } return rv; } @@ -282,7 +303,13 @@ static apr_status_t impl_pollset_poll(apr_pollset_t *pollset, const apr_pollfd_t *fd; for (i = 0, j = 0; i < ret; i++) { - fd = &((pfd_elem_t *)pollset->p->ke_set[i].udata)->pfd; + if (pollset->flags & APR_POLLSET_NOCOPY) { + fd = (apr_pollfd_t *)pollset->p->ke_set[i].udata; + } + else { + fd = &((pfd_elem_t *)pollset->p->ke_set[i].udata)->pfd; + } + if ((pollset->flags & APR_POLLSET_WAKEABLE) && fd->desc_type == APR_POLL_FILE && fd->desc.f == pollset->wakeup_pipe[0]) { @@ -305,13 +332,15 @@ static apr_status_t impl_pollset_poll(apr_pollset_t *pollset, } } - pollset_lock_rings(); + if (!(pollset->flags & APR_POLLSET_NOCOPY)) { + pollset_lock_rings(); - /* Shift all PFDs in the Dead Ring to the Free Ring */ - APR_RING_CONCAT(&(pollset->p->free_ring), &(pollset->p->dead_ring), - pfd_elem_t, link); + /* Shift all PFDs in the Dead Ring to the Free Ring */ + APR_RING_CONCAT(&(pollset->p->free_ring), &(pollset->p->dead_ring), + pfd_elem_t, link); - pollset_unlock_rings(); + pollset_unlock_rings(); + } return rv; } diff --git a/test/testbuckets.c b/test/testbuckets.c index 2b789f1a0..3957f0e2d 100644 --- a/test/testbuckets.c +++ b/test/testbuckets.c @@ -100,12 +100,12 @@ static void flatten_match(abts_case *tc, const char *ctx, apr_size_t len = elen; char msg[200]; - sprintf(msg, "%s: flatten brigade", ctx); + apr_snprintf(msg, sizeof msg, "%s: flatten brigade", ctx); APR_ASSERT_SUCCESS(tc, msg, apr_brigade_flatten(bb, buf, &len)); - sprintf(msg, "%s: length match (%ld not %ld)", ctx, - (long)len, (long)elen); + apr_snprintf(msg, sizeof msg, "%s: length match (%ld not %ld)", ctx, + (long)len, (long)elen); ABTS_ASSERT(tc, msg, len == elen); - sprintf(msg, "%s: result match", ctx); + apr_snprintf(msg, sizeof msg, "%s: result match", ctx); ABTS_STR_NEQUAL(tc, expect, buf, len); free(buf); } diff --git a/threadproc/beos/proc.c b/threadproc/beos/proc.c index e3698082f..cd6f9a250 100644 --- a/threadproc/beos/proc.c +++ b/threadproc/beos/proc.c @@ -170,6 +170,9 @@ APR_DECLARE(apr_status_t) apr_proc_fork(apr_proc_t *proc, apr_pool_t *pool) } } +#if AP_HAS_THREAD_LOCAL + apr_thread_current_after_fork(); +#endif proc->pid = pid; proc->in = NULL; proc->out = NULL; diff --git a/threadproc/beos/thread.c b/threadproc/beos/thread.c index 988f8f4ff..f5752a81e 100644 --- a/threadproc/beos/thread.c +++ b/threadproc/beos/thread.c @@ -62,40 +62,51 @@ APR_DECLARE(apr_status_t) apr_threadattr_guardsize_set(apr_threadattr_t *attr, return APR_ENOTIMPL; } +#if APR_HAS_THREAD_LOCAL +static APR_THREAD_LOCAL apr_thread_t *current_thread = NULL; +#endif + static void *dummy_worker(void *opaque) { apr_thread_t *thd = (apr_thread_t*)opaque; void *ret; +#if APR_HAS_THREAD_LOCAL + current_thread = thd; +#endif + apr_pool_owner_set(thd->pool, 0); ret = thd->func(thd, thd->data); if (thd->detached) { apr_pool_destroy(thd->pool); } + 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_abortfunc_t abort_fn = apr_pool_abort_get(pool); 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); if (stat != APR_SUCCESS) { + if (abort_fn) + abort_fn(stat); return stat; } - stat = apr_pool_create_unmanaged_ex(&p, apr_pool_abort_get(pool), - allocator); + stat = apr_pool_create_unmanaged_ex(&p, abort_fn, allocator); if (stat != APR_SUCCESS) { apr_allocator_destroy(allocator); return stat; @@ -114,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 @@ -126,13 +153,54 @@ 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) { + *current = NULL; + return stat; + } + + (*current)->td = apr_os_thread_current(); + +#if APR_HAS_THREAD_LOCAL + current_thread = *current; +#endif + return APR_SUCCESS; +} + +APR_DECLARE(void) apr_thread_current_after_fork(void) +{ +#if APR_HAS_THREAD_LOCAL + current_thread = NULL; +#endif +} + +APR_DECLARE(apr_thread_t *) apr_thread_current(void) +{ +#if 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); @@ -197,6 +265,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); } @@ -204,6 +276,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/proc.c b/threadproc/netware/proc.c index f5d24b21b..1a6de7b7b 100644 --- a/threadproc/netware/proc.c +++ b/threadproc/netware/proc.c @@ -226,6 +226,9 @@ APR_DECLARE(apr_status_t) apr_proc_fork(apr_proc_t *proc, apr_pool_t *pool) return errno; } else if (pid == 0) { +#if AP_HAS_THREAD_LOCAL + apr_thread_current_after_fork(); +#endif proc->pid = pid; proc->in = NULL; proc->out = NULL; diff --git a/threadproc/netware/thread.c b/threadproc/netware/thread.c index a661ef886..24122119a 100644 --- a/threadproc/netware/thread.c +++ b/threadproc/netware/thread.c @@ -64,43 +64,51 @@ APR_DECLARE(apr_status_t) apr_threadattr_guardsize_set(apr_threadattr_t *attr, return APR_ENOTIMPL; } +#if APR_HAS_THREAD_LOCAL +static APR_THREAD_LOCAL apr_thread_t *current_thread = NULL; +#endif + static void *dummy_worker(void *opaque) { apr_thread_t *thd = (apr_thread_t *)opaque; void *ret; +#if APR_HAS_THREAD_LOCAL + current_thread = thd; +#endif + apr_pool_owner_set(thd->pool, 0); ret = thd->func(thd, thd->data); if (thd->detached) { apr_pool_destroy(thd->pool); } + 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_abortfunc_t abort_fn = apr_pool_abort_get(pool); 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); if (stat != APR_SUCCESS) { + if (abort_fn) + abort_fn(stat); return stat; } - stat = apr_pool_create_unmanaged_ex(&p, apr_pool_abort_get(pool), - allocator); + stat = apr_pool_create_unmanaged_ex(&p, abort_fn, allocator); if (stat != APR_SUCCESS) { apr_allocator_destroy(allocator); return stat; @@ -131,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. @@ -139,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), @@ -151,7 +177,7 @@ apr_status_t apr_thread_create(apr_thread_t **new, /* size_t stackSize */ stack_size, /* unsigned long flags */ NX_CTX_NORMAL, /* int *error */ &stat); - + (void) NXContextSetName( /* NXContext_t ctx */ (*new)->ctx, /* const char *name */ (*new)->thread_name); @@ -162,13 +188,54 @@ 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) { + *current = NULL; return stat; } - + + (*current)->td = apr_os_thread_current(); + +#if APR_HAS_THREAD_LOCAL + current_thread = *current; +#endif return APR_SUCCESS; } +APR_DECLARE(void) apr_thread_current_after_fork(void) +{ +#if APR_HAS_THREAD_LOCAL + current_thread = NULL; +#endif +} + +APR_DECLARE(apr_thread_t *) apr_thread_current(void) +{ +#if APR_HAS_THREAD_LOCAL + return current_thread; +#else + return NULL; +#endif +} + apr_os_thread_t apr_os_thread_current() { return NXThreadGetId(); @@ -227,26 +294,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/proc.c b/threadproc/os2/proc.c index cd7500129..beb100908 100644 --- a/threadproc/os2/proc.c +++ b/threadproc/os2/proc.c @@ -227,6 +227,9 @@ APR_DECLARE(apr_status_t) apr_proc_fork(apr_proc_t *proc, apr_pool_t *pool) return errno; } else if (pid == 0) { +#if AP_HAS_THREAD_LOCAL + apr_thread_current_after_fork(); +#endif proc->pid = pid; proc->in = NULL; proc->out = NULL; diff --git a/threadproc/os2/thread.c b/threadproc/os2/thread.c index 2891f0577..e0540188d 100644 --- a/threadproc/os2/thread.c +++ b/threadproc/os2/thread.c @@ -68,8 +68,16 @@ APR_DECLARE(apr_status_t) apr_threadattr_guardsize_set(apr_threadattr_t *attr, return APR_ENOTIMPL; } +#if APR_HAS_THREAD_LOCAL +static APR_THREAD_LOCAL apr_thread_t *current_thread = NULL; +#endif + static void dummy_worker(void *opaque) { +#if APR_HAS_THREAD_LOCAL + current_thread = thread; +#endif + apr_thread_t *thread = (apr_thread_t *)opaque; apr_pool_owner_set(thread->pool, 0); thread->exitval = thread->func(thread, thread->data); @@ -80,26 +88,29 @@ static void dummy_worker(void *opaque) -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_abortfunc_t abort_fn = apr_pool_abort_get(pool); 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); if (stat != APR_SUCCESS) { + if (abort_fn) + abort_fn(stat); return stat; } - stat = apr_pool_create_unmanaged_ex(&p, apr_pool_abort_get(pool), - allocator); + stat = apr_pool_create_unmanaged_ex(&p, abort_fn, allocator); if (stat != APR_SUCCESS) { apr_allocator_destroy(allocator); return stat; @@ -124,19 +135,74 @@ 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(current, attr, NULL, NULL, pool); + if (stat != APR_SUCCESS) { + *current = NULL; return stat; } + (*current)->tid = apr_os_thread_current(); + +#if APR_HAS_THREAD_LOCAL + current_thread = *current; +#endif return APR_SUCCESS; } +APR_DECLARE(void) apr_thread_current_after_fork(void) +{ +#if APR_HAS_THREAD_LOCAL + current_thread = NULL; +#endif +} + +APR_DECLARE(apr_thread_t *) apr_thread_current(void) +{ +#if APR_HAS_THREAD_LOCAL + return current_thread; +#else + return NULL; +#endif +} APR_DECLARE(apr_os_thread_t) apr_os_thread_current() @@ -232,6 +298,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 +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); } diff --git a/threadproc/unix/proc.c b/threadproc/unix/proc.c index ed7a05fda..ad31c814f 100644 --- a/threadproc/unix/proc.c +++ b/threadproc/unix/proc.c @@ -234,6 +234,9 @@ APR_DECLARE(apr_status_t) apr_proc_fork(apr_proc_t *proc, apr_pool_t *pool) return errno; } else if (pid == 0) { +#if AP_HAS_THREAD_LOCAL + apr_thread_current_after_fork(); +#endif proc->pid = getpid(); /* Do the work needed for children PRNG(s). */ diff --git a/threadproc/unix/thread.c b/threadproc/unix/thread.c index d1ae872c6..209fe7c86 100644 --- a/threadproc/unix/thread.c +++ b/threadproc/unix/thread.c @@ -136,42 +136,51 @@ APR_DECLARE(apr_status_t) apr_threadattr_guardsize_set(apr_threadattr_t *attr, #endif } +#if APR_HAS_THREAD_LOCAL +static APR_THREAD_LOCAL apr_thread_t *current_thread = NULL; +#endif + static void *dummy_worker(void *opaque) { apr_thread_t *thread = (apr_thread_t*)opaque; void *ret; +#if APR_HAS_THREAD_LOCAL + current_thread = thread; +#endif + apr_pool_owner_set(thread->pool, 0); ret = thread->func(thread, thread->data); if (thread->detached) { apr_pool_destroy(thread->pool); } + 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_abortfunc_t abort_fn = apr_pool_abort_get(pool); 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); if (stat != APR_SUCCESS) { + if (abort_fn) + abort_fn(stat); return stat; } - stat = apr_pool_create_unmanaged_ex(&p, apr_pool_abort_get(pool), - allocator); + stat = apr_pool_create_unmanaged_ex(&p, abort_fn, allocator); if (stat != APR_SUCCESS) { apr_allocator_destroy(allocator); return stat; @@ -194,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 @@ -203,13 +229,54 @@ 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) { + *current = NULL; + return stat; + } + + *(*current)->td = apr_os_thread_current(); + +#if APR_HAS_THREAD_LOCAL + current_thread = *current; +#endif + return APR_SUCCESS; +} + +APR_DECLARE(void) apr_thread_current_after_fork(void) +{ +#if APR_HAS_THREAD_LOCAL + current_thread = NULL; +#endif +} + +APR_DECLARE(apr_thread_t *) apr_thread_current(void) +{ +#if 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(); @@ -297,6 +364,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 +375,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 569268cd1..7e1c1a8be 100644 --- a/threadproc/win32/thread.c +++ b/threadproc/win32/thread.c @@ -72,43 +72,52 @@ APR_DECLARE(apr_status_t) apr_threadattr_guardsize_set(apr_threadattr_t *attr, return APR_ENOTIMPL; } +#if APR_HAS_THREAD_LOCAL +static APR_THREAD_LOCAL apr_thread_t *current_thread = NULL; +#endif + static void *dummy_worker(void *opaque) { apr_thread_t *thd = (apr_thread_t *)opaque; void *ret; +#if APR_HAS_THREAD_LOCAL + current_thread = thd; +#endif + TlsSetValue(tls_apr_thread, thd->td); apr_pool_owner_set(thd->pool, 0); ret = thd->func(thd, thd->data); if (!thd->td) { /* detached? */ apr_pool_destroy(thd->pool); } + 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_abortfunc_t abort_fn = apr_pool_abort_get(pool); 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); if (stat != APR_SUCCESS) { + if (abort_fn) + abort_fn(stat); return stat; } - stat = apr_pool_create_unmanaged_ex(&p, apr_pool_abort_get(pool), - allocator); + stat = apr_pool_create_unmanaged_ex(&p, abort_fn, allocator); if (stat != APR_SUCCESS) { apr_allocator_destroy(allocator); return stat; @@ -125,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,9 +159,10 @@ 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; } + if (attr && attr->detach) { CloseHandle(handle); } @@ -146,6 +173,49 @@ 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) { + *current = NULL; + return stat; + } + + if (!(attr && attr->detach)) { + (*current)->td = apr_os_thread_current(); + } + +#if APR_HAS_THREAD_LOCAL + current_thread = *current; +#endif + return APR_SUCCESS; +} + +APR_DECLARE(void) apr_thread_current_after_fork(void) +{ +#if APR_HAS_THREAD_LOCAL + current_thread = NULL; +#endif +} + +APR_DECLARE(apr_thread_t *) apr_thread_current(void) +{ +#if APR_HAS_THREAD_LOCAL + return current_thread; +#else + return NULL; +#endif +} + APR_DECLARE(void) apr_thread_exit(apr_thread_t *thd, apr_status_t retval) { thd->exited = 1; @@ -153,6 +223,9 @@ APR_DECLARE(void) apr_thread_exit(apr_thread_t *thd, apr_status_t retval) if (!thd->td) { /* detached? */ apr_pool_destroy(thd->pool); } +#if APR_HAS_THREAD_LOCAL + current_thread = NULL; +#endif _endthreadex(0); } @@ -209,6 +282,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); } @@ -216,6 +293,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