summaryrefslogtreecommitdiff
path: root/locks/unix
diff options
context:
space:
mode:
authorYann Ylavic <ylavic@apache.org>2016-03-05 09:29:08 +0000
committerYann Ylavic <ylavic@apache.org>2016-03-05 09:29:08 +0000
commitffac62e0d835b86cdb23cb54f27786d84302ab34 (patch)
tree5c169836822a5d09eae16266ed7183f5a27bae6c /locks/unix
parent8cad15fe3632a1a4246a847ce11a63587a007632 (diff)
downloadapr-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.c54
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"
};