diff options
author | Yann Ylavic <ylavic@apache.org> | 2017-04-05 22:50:27 +0000 |
---|---|---|
committer | Yann Ylavic <ylavic@apache.org> | 2017-04-05 22:50:27 +0000 |
commit | c485e779e650aac535587c90d0e631fb5b6fe7db (patch) | |
tree | 39cdc61cbc46553efcbfabdb2fee2cdf723d63cc /locks | |
parent | 67b59759a6928985dad16cf88ed5379c5433dd84 (diff) | |
download | apr-c485e779e650aac535587c90d0e631fb5b6fe7db.tar.gz |
locks: when pthread_mutex_timedlock() isn't available, fall back to an
implementation based on pthread_cond_timedwait() when possible.
git-svn-id: https://svn.apache.org/repos/asf/apr/apr/trunk@1790330 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'locks')
-rw-r--r-- | locks/unix/proc_mutex.c | 301 | ||||
-rw-r--r-- | locks/unix/thread_mutex.c | 67 |
2 files changed, 318 insertions, 50 deletions
diff --git a/locks/unix/proc_mutex.c b/locks/unix/proc_mutex.c index 990bd15f0..8fc0bd2d9 100644 --- a/locks/unix/proc_mutex.c +++ b/locks/unix/proc_mutex.c @@ -423,6 +423,12 @@ static const apr_proc_mutex_unix_lock_methods_t mutex_sysv_methods = #if APR_HAS_PROC_PTHREAD_SERIALIZE +#if defined(HAVE_PTHREAD_MUTEX_ROBUST) \ + && defined(HAVE_PTHREAD_CONDATTR_SETPSHARED) \ + && !defined(HAVE_PTHREAD_MUTEX_TIMEDLOCK) +#define USE_PTHREAD_MUTEX_COND +#endif + /* The mmap()ed pthread_interproc is the native pthread_mutex_t followed * by a refcounter to track children using it. We want to avoid calling * pthread_mutex_destroy() on the shared mutex area while it is in use by @@ -434,12 +440,27 @@ static const apr_proc_mutex_unix_lock_methods_t mutex_sysv_methods = */ typedef struct { pthread_mutex_t mutex; +#ifdef USE_PTHREAD_MUTEX_COND + pthread_cond_t cond; + apr_int32_t cond_locked; + apr_uint32_t cond_num_waiters; +#define proc_pthread_mutex_cond(m) \ + (((proc_pthread_mutex_t *)(m)->os.pthread_interproc)->cond) +#define proc_pthread_mutex_cond_locked(m) \ + (((proc_pthread_mutex_t *)(m)->os.pthread_interproc)->cond_locked) +#define proc_pthread_mutex_cond_num_waiters(m) \ + (((proc_pthread_mutex_t *)(m)->os.pthread_interproc)->cond_num_waiters) +#endif /* USE_PTHREAD_MUTEX_COND */ apr_uint32_t refcount; } proc_pthread_mutex_t; #define proc_pthread_mutex_refcount(m) \ (((proc_pthread_mutex_t *)(m)->os.pthread_interproc)->refcount) +static apr_status_t proc_mutex_pthread_timedacquire(apr_proc_mutex_t *mutex, + apr_time_t timeout, + int absolute); + static APR_INLINE int proc_pthread_mutex_inc(apr_proc_mutex_t *mutex) { if (mutex->pthread_refcounting) { @@ -471,6 +492,16 @@ static apr_status_t proc_pthread_mutex_unref(void *mutex_) } } if (!proc_pthread_mutex_dec(mutex)) { +#ifdef USE_PTHREAD_MUTEX_COND + if (proc_pthread_mutex_cond_locked(mutex) != -1 && + (rv = pthread_cond_destroy(&proc_pthread_mutex_cond(mutex)))) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif + return rv; + } +#endif /* USE_PTHREAD_MUTEX_COND */ + if ((rv = pthread_mutex_destroy(mutex->os.pthread_interproc))) { #ifdef HAVE_ZOS_PTHREADS rv = errno; @@ -523,6 +554,9 @@ static apr_status_t proc_mutex_pthread_create(apr_proc_mutex_t *new_mutex, new_mutex->pthread_refcounting = 1; new_mutex->curr_locked = -1; /* until the mutex has been created */ +#ifdef USE_PTHREAD_MUTEX_COND + proc_pthread_mutex_cond_locked(new_mutex) = -1; +#endif if ((rv = pthread_mutexattr_init(&mattr))) { #ifdef HAVE_ZOS_PTHREADS @@ -601,64 +635,129 @@ static apr_status_t proc_mutex_pthread_child_init(apr_proc_mutex_t **mutex, static apr_status_t proc_mutex_pthread_acquire(apr_proc_mutex_t *mutex) { - apr_status_t rv; - - if ((rv = pthread_mutex_lock(mutex->os.pthread_interproc))) { -#ifdef HAVE_ZOS_PTHREADS - rv = errno; -#endif -#ifdef HAVE_PTHREAD_MUTEX_ROBUST - /* Okay, our owner died. Let's try to make it consistent again. */ - if (rv == EOWNERDEAD) { - proc_pthread_mutex_dec(mutex); - pthread_mutex_consistent_np(mutex->os.pthread_interproc); - } - else -#endif - return rv; - } - mutex->curr_locked = 1; - return APR_SUCCESS; + return proc_mutex_pthread_timedacquire(mutex, -1, 0); } static apr_status_t proc_mutex_pthread_tryacquire(apr_proc_mutex_t *mutex) { + return proc_mutex_pthread_timedacquire(mutex, 0, 0); +} + +static apr_status_t proc_mutex_pthread_timedacquire(apr_proc_mutex_t *mutex, + apr_time_t timeout, + int absolute) +{ apr_status_t rv; - - if ((rv = pthread_mutex_trylock(mutex->os.pthread_interproc))) { + +#ifdef USE_PTHREAD_MUTEX_COND + if (proc_pthread_mutex_cond_locked(mutex) != -1) { + if ((rv = pthread_mutex_lock(mutex->os.pthread_interproc))) { #ifdef HAVE_ZOS_PTHREADS - rv = errno; + rv = errno; #endif - if (rv == EBUSY) { - return APR_EBUSY; - } #ifdef HAVE_PTHREAD_MUTEX_ROBUST - /* Okay, our owner died. Let's try to make it consistent again. */ - if (rv == EOWNERDEAD) { - proc_pthread_mutex_dec(mutex); - pthread_mutex_consistent_np(mutex->os.pthread_interproc); + /* Okay, our owner died. Let's try to make it consistent again. */ + if (rv == EOWNERDEAD) { + proc_pthread_mutex_dec(mutex); + pthread_mutex_consistent_np(mutex->os.pthread_interproc); + } + else +#endif + return rv; + } + + if (!proc_pthread_mutex_cond_locked(mutex)) { + proc_pthread_mutex_cond_locked(mutex) = 1; + } + else if (timeout == 0) { + rv = APR_EBUSY; } - else + else { + proc_pthread_mutex_cond_num_waiters(mutex)++; + if (timeout < 0) { + rv = pthread_cond_wait(&proc_pthread_mutex_cond(mutex), + mutex->os.pthread_interproc); +#ifdef HAVE_ZOS_PTHREADS + if (rv) { + rv = errno; + } #endif - return rv; - } - mutex->curr_locked = 1; - return APR_SUCCESS; -} + } + else { + struct timespec abstime; + if (!absolute) { + timeout += apr_time_now(); + } + abstime.tv_sec = apr_time_sec(timeout); + abstime.tv_nsec = apr_time_usec(timeout) * 1000; /* nanoseconds */ + rv = pthread_cond_timedwait(&proc_pthread_mutex_cond(mutex), + mutex->os.pthread_interproc, + &abstime); + if (rv) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif + if (rv == ETIMEDOUT) { + rv = APR_TIMEUP; + } + } + } + proc_pthread_mutex_cond_num_waiters(mutex)--; + } + if (rv) { + pthread_mutex_unlock(mutex->os.pthread_interproc); + return rv; + } -static apr_status_t proc_mutex_pthread_timedacquire(apr_proc_mutex_t *mutex, - apr_time_t timeout, - int absolute) -{ -#ifndef HAVE_PTHREAD_MUTEX_TIMEDLOCK -extern int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *abs_timeout); + rv = pthread_mutex_unlock(mutex->os.pthread_interproc); + if (rv) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; #endif - if (timeout < 0) { - return proc_mutex_pthread_acquire(mutex); + return rv; + } + } + else +#endif /* USE_PTHREAD_MUTEX_COND */ + if (timeout <= 0) { + if (timeout < 0) { + rv = pthread_mutex_lock(mutex->os.pthread_interproc); + if (rv) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif + } + } + else { + rv = pthread_mutex_trylock(mutex->os.pthread_interproc); + if (rv) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif + if (rv == EBUSY) { + rv = APR_EBUSY; + } + } + } + if (rv) { +#ifdef HAVE_PTHREAD_MUTEX_ROBUST + /* Okay, our owner died. Let's try to make it consistent again. */ + if (rv == EOWNERDEAD) { + proc_pthread_mutex_dec(mutex); + pthread_mutex_consistent_np(mutex->os.pthread_interproc); + } + else +#endif + return rv; + } } else { apr_status_t rv; struct timespec abstime; +#ifndef HAVE_PTHREAD_MUTEX_TIMEDLOCK + extern int pthread_mutex_timedlock(pthread_mutex_t *mutex, + const struct timespec *abs_timeout); +#endif if (!absolute) { timeout += apr_time_now(); @@ -671,9 +770,6 @@ extern int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec #ifdef HAVE_ZOS_PTHREADS rv = errno; #endif - if (rv == ETIMEDOUT) { - return APR_TIMEUP; - } #ifdef HAVE_PTHREAD_MUTEX_ROBUST /* Okay, our owner died. Let's try to make it consistent again. */ if (rv == EOWNERDEAD) { @@ -682,9 +778,15 @@ extern int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec } else #endif - return rv; + if (rv == ETIMEDOUT) { + return APR_TIMEUP; + } + else { + return rv; + } } } + mutex->curr_locked = 1; return APR_SUCCESS; } @@ -693,6 +795,45 @@ static apr_status_t proc_mutex_pthread_release(apr_proc_mutex_t *mutex) { apr_status_t rv; +#ifdef USE_PTHREAD_MUTEX_COND + if (proc_pthread_mutex_cond_locked(mutex) != -1) { + if ((rv = pthread_mutex_lock(mutex->os.pthread_interproc))) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif +#ifdef HAVE_PTHREAD_MUTEX_ROBUST + /* Okay, our owner died. Let's try to make it consistent again. */ + if (rv == EOWNERDEAD) { + proc_pthread_mutex_dec(mutex); + pthread_mutex_consistent_np(mutex->os.pthread_interproc); + } + else +#endif + return rv; + } + + if (!proc_pthread_mutex_cond_locked(mutex)) { + rv = APR_EINVAL; + } + else if (proc_pthread_mutex_cond_num_waiters(mutex)) { + rv = pthread_cond_signal(&proc_pthread_mutex_cond(mutex)); + if (rv) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif + } + } + else { + proc_pthread_mutex_cond_locked(mutex) = 0; + rv = APR_SUCCESS; + } + if (rv) { + pthread_mutex_unlock(mutex->os.pthread_interproc); + return rv; + } + } +#endif /* USE_PTHREAD_MUTEX_COND */ + mutex->curr_locked = 0; if ((rv = pthread_mutex_unlock(mutex->os.pthread_interproc))) { #ifdef HAVE_ZOS_PTHREADS @@ -700,6 +841,7 @@ static apr_status_t proc_mutex_pthread_release(apr_proc_mutex_t *mutex) #endif return rv; } + return APR_SUCCESS; } @@ -718,6 +860,69 @@ static const apr_proc_mutex_unix_lock_methods_t mutex_proc_pthread_methods = "pthread" }; +#ifdef USE_PTHREAD_MUTEX_COND +static apr_status_t proc_mutex_pthread_cond_create(apr_proc_mutex_t *new_mutex, + const char *fname) +{ + apr_status_t rv; + pthread_condattr_t cattr; + + rv = proc_mutex_pthread_create(new_mutex, fname); + if (rv != APR_SUCCESS) { + return rv; + } + + if ((rv = pthread_condattr_init(&cattr))) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif + apr_pool_cleanup_run(new_mutex->pool, new_mutex, + apr_proc_mutex_cleanup); + return rv; + } + if ((rv = pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_SHARED))) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif + pthread_condattr_destroy(&cattr); + apr_pool_cleanup_run(new_mutex->pool, new_mutex, + apr_proc_mutex_cleanup); + return rv; + } + if ((rv = pthread_cond_init(&proc_pthread_mutex_cond(new_mutex), + &cattr))) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif + pthread_condattr_destroy(&cattr); + apr_pool_cleanup_run(new_mutex->pool, new_mutex, + apr_proc_mutex_cleanup); + return rv; + } + pthread_condattr_destroy(&cattr); + + proc_pthread_mutex_cond_locked(new_mutex) = 0; + proc_pthread_mutex_cond_num_waiters(new_mutex) = 0; + + return APR_SUCCESS; +} + +static const apr_proc_mutex_unix_lock_methods_t mutex_proc_pthread_cond_methods = +{ + APR_PROCESS_LOCK_MECH_IS_GLOBAL, + proc_mutex_pthread_cond_create, + proc_mutex_pthread_acquire, + proc_mutex_pthread_tryacquire, + proc_mutex_pthread_timedacquire, + proc_mutex_pthread_release, + proc_mutex_pthread_cleanup, + proc_mutex_pthread_child_init, + proc_mutex_no_perms_set, + APR_LOCK_DEFAULT_TIMED, + "default_timed" +}; +#endif + #endif #if APR_HAS_FCNTL_SERIALIZE @@ -1216,7 +1421,11 @@ static apr_status_t proc_mutex_choose_method(apr_proc_mutex_t *new_mutex, case APR_LOCK_DEFAULT_TIMED: #if APR_HAS_PROC_PTHREAD_SERIALIZE \ && defined(HAVE_PTHREAD_MUTEX_ROBUST) +#ifdef USE_PTHREAD_MUTEX_COND + new_mutex->meth = &mutex_proc_pthread_cond_methods; +#else new_mutex->meth = &mutex_proc_pthread_methods; +#endif #elif APR_HAS_SYSVSEM_SERIALIZE \ && defined(HAVE_SEMTIMEDOP) new_mutex->meth = &mutex_sysv_methods; diff --git a/locks/unix/thread_mutex.c b/locks/unix/thread_mutex.c index 5c6716658..fe515b2e6 100644 --- a/locks/unix/thread_mutex.c +++ b/locks/unix/thread_mutex.c @@ -77,6 +77,19 @@ APR_DECLARE(apr_status_t) apr_thread_mutex_create(apr_thread_mutex_t **mutex, return rv; } +#ifndef HAVE_PTHREAD_MUTEX_TIMEDLOCK + if (flags & APR_THREAD_MUTEX_TIMED) { + rv = apr_thread_cond_create(&new_mutex->cond, pool); + if (rv) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif + pthread_mutex_destroy(&new_mutex->mutex); + return rv; + } + } +#endif + apr_pool_cleanup_register(new_mutex->pool, new_mutex, thread_mutex_cleanup, apr_pool_cleanup_null); @@ -182,10 +195,7 @@ APR_DECLARE(apr_status_t) apr_thread_mutex_timedlock(apr_thread_mutex_t *mutex, { apr_status_t rv = APR_ENOTIMPL; -#ifndef HAVE_PTHREAD_MUTEX_TIMEDLOCK -extern int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec *abs_timeout); -#endif - +#ifdef HAVE_PTHREAD_MUTEX_TIMEDLOCK if (timeout < 0) { rv = pthread_mutex_lock(&mutex->mutex); if (rv) { @@ -213,6 +223,55 @@ extern int pthread_mutex_timedlock(pthread_mutex_t *mutex, const struct timespec } } } + +#else /* HAVE_PTHREAD_MUTEX_TIMEDLOCK */ + + if (mutex->cond) { + apr_status_t rv2; + + rv = pthread_mutex_lock(&mutex->mutex); + if (rv) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif + return rv; + } + + if (mutex->locked) { + mutex->num_waiters++; + if (timeout < 0) { + rv = apr_thread_cond_wait(mutex->cond, mutex); + } + else { + if (absolute) { + apr_time_t now = apr_time_now(); + if (timeout > now) { + timeout -= now; + } + else { + timeout = 0; + } + } + rv = apr_thread_cond_timedwait(mutex->cond, mutex, timeout); + } + mutex->num_waiters--; + } + else { + mutex->locked = 1; + } + + rv2 = pthread_mutex_unlock(&mutex->mutex); + if (rv2 && !rv) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#else + rv = rv2; +#endif + } + } + +#endif /* HAVE_PTHREAD_MUTEX_TIMEDLOCK */ + return rv; } |