diff options
author | ylavic <ylavic@13f79535-47bb-0310-9956-ffa450edef68> | 2016-04-12 12:40:49 +0000 |
---|---|---|
committer | ylavic <ylavic@13f79535-47bb-0310-9956-ffa450edef68> | 2016-04-12 12:40:49 +0000 |
commit | c1cb6fd7ed890744f1eeee0180c70f6b518e21a7 (patch) | |
tree | f44f3f2b20c89ab1ac42fc28c1f323ee4f1cbda7 /locks | |
parent | 76e8433c89d28f9dadee86fb116febe0e7a52f16 (diff) | |
download | libapr-c1cb6fd7ed890744f1eeee0180c70f6b518e21a7.tar.gz |
Merge r1733694, r1733706, r1733708 from trunk:
apr_proc_mutex-pthread: Refcount shared mutexes usage to avoid
destruction while still is use by some process(es).
PR 49504.
apr_proc_mutex-pthread: follow up to r1733694.
Add missing refcount decrement when recovering the mutex from died owner,
like in proc_mutex_proc_pthread_acquire() but this time for
proc_mutex_proc_pthread_tryacquire() and proc_mutex_proc_pthread_timedacquire().
apr_proc_mutex-pthread: follow up to r1733694.
Simplify #if/#else/#endif logic, no functional change.
git-svn-id: http://svn.apache.org/repos/asf/apr/apr/branches/1.6.x@1738793 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'locks')
-rw-r--r-- | locks/unix/proc_mutex.c | 70 |
1 files changed, 54 insertions, 16 deletions
diff --git a/locks/unix/proc_mutex.c b/locks/unix/proc_mutex.c index 0a4cf180d..27b9577dd 100644 --- a/locks/unix/proc_mutex.c +++ b/locks/unix/proc_mutex.c @@ -19,6 +19,7 @@ #include "apr_arch_proc_mutex.h" #include "apr_arch_file_io.h" /* for apr_mkstemp() */ #include "apr_hash.h" +#include "apr_atomic.h" APR_DECLARE(apr_status_t) apr_proc_mutex_destroy(apr_proc_mutex_t *mutex) { @@ -427,7 +428,24 @@ static const apr_proc_mutex_unix_lock_methods_t mutex_sysv_methods = #if APR_HAS_PROC_PTHREAD_SERIALIZE -static apr_status_t proc_mutex_proc_pthread_cleanup(void *mutex_) +/* 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 + * another process, because this may mark the shared pthread_mutex_t as + * invalid for everyone, including forked children (unlike "sysvsem" for + * example), causing unexpected errors or deadlocks (PR 49504). So the + * last process (parent or child) referencing the mutex will effectively + * destroy it. + */ +typedef struct { + pthread_mutex_t mutex; + apr_uint32_t refcount; +} proc_pthread_mutex_t; + +#define proc_pthread_mutex_refcount(m) \ + (((proc_pthread_mutex_t *)(m)->pthread_interproc)->refcount) + +static apr_status_t proc_pthread_mutex_unref(void *mutex_) { apr_proc_mutex_t *mutex=mutex_; apr_status_t rv; @@ -440,8 +458,7 @@ static apr_status_t proc_mutex_proc_pthread_cleanup(void *mutex_) return rv; } } - /* curr_locked is set to -1 until the mutex has been created */ - if (mutex->curr_locked != -1) { + if (!apr_atomic_dec32(&proc_pthread_mutex_refcount(mutex))) { if ((rv = pthread_mutex_destroy(mutex->pthread_interproc))) { #ifdef HAVE_ZOS_PTHREADS rv = errno; @@ -449,6 +466,20 @@ static apr_status_t proc_mutex_proc_pthread_cleanup(void *mutex_) return rv; } } + return APR_SUCCESS; +} + +static apr_status_t proc_mutex_proc_pthread_cleanup(void *mutex_) +{ + apr_proc_mutex_t *mutex=mutex_; + apr_status_t rv; + + /* curr_locked is set to -1 until the mutex has been created */ + if (mutex->curr_locked != -1) { + if ((rv = proc_pthread_mutex_unref(mutex))) { + return rv; + } + } if (munmap((caddr_t)mutex->pthread_interproc, sizeof(pthread_mutex_t))) { return errno; } @@ -469,7 +500,7 @@ static apr_status_t proc_mutex_proc_pthread_create(apr_proc_mutex_t *new_mutex, new_mutex->pthread_interproc = (pthread_mutex_t *)mmap( (caddr_t) 0, - sizeof(pthread_mutex_t), + sizeof(proc_pthread_mutex_t), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (new_mutex->pthread_interproc == (pthread_mutex_t *) (caddr_t) -1) { @@ -525,6 +556,7 @@ static apr_status_t proc_mutex_proc_pthread_create(apr_proc_mutex_t *new_mutex, return rv; } + proc_pthread_mutex_refcount(new_mutex) = 1; /* first/parent reference */ new_mutex->curr_locked = 0; /* mutex created now */ if ((rv = pthread_mutexattr_destroy(&mattr))) { @@ -542,6 +574,17 @@ static apr_status_t proc_mutex_proc_pthread_create(apr_proc_mutex_t *new_mutex, return APR_SUCCESS; } +static apr_status_t proc_mutex_proc_pthread_child_init(apr_proc_mutex_t **mutex, + apr_pool_t *pool, + const char *fname) +{ + (*mutex)->curr_locked = 0; + apr_atomic_inc32(&proc_pthread_mutex_refcount(*mutex)); + apr_pool_cleanup_register(pool, *mutex, proc_pthread_mutex_unref, + apr_pool_cleanup_null); + return APR_SUCCESS; +} + static apr_status_t proc_mutex_proc_pthread_acquire(apr_proc_mutex_t *mutex) { apr_status_t rv; @@ -553,13 +596,12 @@ static apr_status_t proc_mutex_proc_pthread_acquire(apr_proc_mutex_t *mutex) #ifdef HAVE_PTHREAD_MUTEX_ROBUST /* Okay, our owner died. Let's try to make it consistent again. */ if (rv == EOWNERDEAD) { + apr_atomic_dec32(&proc_pthread_mutex_refcount(mutex)); pthread_mutex_consistent_np(mutex->pthread_interproc); } else - return rv; -#else - return rv; #endif + return rv; } mutex->curr_locked = 1; return APR_SUCCESS; @@ -579,14 +621,12 @@ static apr_status_t proc_mutex_proc_pthread_tryacquire(apr_proc_mutex_t *mutex) #ifdef HAVE_PTHREAD_MUTEX_ROBUST /* Okay, our owner died. Let's try to make it consistent again. */ if (rv == EOWNERDEAD) { + apr_atomic_dec32(&proc_pthread_mutex_refcount(mutex)); pthread_mutex_consistent_np(mutex->pthread_interproc); - rv = APR_SUCCESS; } else - return rv; -#else - return rv; #endif + return rv; } mutex->curr_locked = 1; return APR_SUCCESS; @@ -621,14 +661,12 @@ proc_mutex_proc_pthread_timedacquire(apr_proc_mutex_t *mutex, #ifdef HAVE_PTHREAD_MUTEX_ROBUST /* Okay, our owner died. Let's try to make it consistent again. */ if (rv == EOWNERDEAD) { + apr_atomic_dec32(&proc_pthread_mutex_refcount(mutex)); pthread_mutex_consistent_np(mutex->pthread_interproc); - rv = APR_SUCCESS; } else - return rv; -#else - return rv; #endif + return rv; } } mutex->curr_locked = 1; @@ -658,7 +696,7 @@ static const apr_proc_mutex_unix_lock_methods_t mutex_proc_pthread_methods = proc_mutex_proc_pthread_timedacquire, proc_mutex_proc_pthread_release, proc_mutex_proc_pthread_cleanup, - proc_mutex_no_child_init, + proc_mutex_proc_pthread_child_init, proc_mutex_no_perms_set, "pthread" }; |