diff options
author | Yann Ylavic <ylavic@apache.org> | 2016-03-05 09:29:08 +0000 |
---|---|---|
committer | Yann Ylavic <ylavic@apache.org> | 2016-03-05 09:29:08 +0000 |
commit | ffac62e0d835b86cdb23cb54f27786d84302ab34 (patch) | |
tree | 5c169836822a5d09eae16266ed7183f5a27bae6c /locks/unix | |
parent | 8cad15fe3632a1a4246a847ce11a63587a007632 (diff) | |
download | apr-ffac62e0d835b86cdb23cb54f27786d84302ab34.tar.gz |
apr_proc_mutex-pthread: Refcount shared mutexes usage to avoid
destruction while still is use by some process(es).
PR 49504.
git-svn-id: https://svn.apache.org/repos/asf/apr/apr/trunk@1733694 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'locks/unix')
-rw-r--r-- | locks/unix/proc_mutex.c | 54 |
1 files changed, 49 insertions, 5 deletions
diff --git a/locks/unix/proc_mutex.c b/locks/unix/proc_mutex.c index f66cd6c9c..41830f822 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_md5.h" /* for apr_md5() */ +#include "apr_atomic.h" APR_DECLARE(apr_status_t) apr_proc_mutex_destroy(apr_proc_mutex_t *mutex) { @@ -417,7 +418,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; @@ -430,8 +448,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; @@ -439,6 +456,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; } @@ -459,7 +490,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) { @@ -515,6 +546,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))) { @@ -532,6 +564,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; @@ -543,6 +586,7 @@ 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 @@ -648,7 +692,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" }; |