summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYann Ylavic <ylavic@apache.org>2017-04-06 21:57:29 +0000
committerYann Ylavic <ylavic@apache.org>2017-04-06 21:57:29 +0000
commitc93e1021f0bffe93d548b372b10704b8584c58f9 (patch)
tree40af729ab76afc3f2785b5f30e60b246d2dfe4ba
parentcb035cfba978f8c8e92b0b013543ea56b9a094f1 (diff)
downloadapr-c93e1021f0bffe93d548b372b10704b8584c58f9.tar.gz
Merge r1790296, r1790302, r1790303, r1790304, r1790330, r1790331, r1790436, r1790439, r1790444, r1790446 from trunk:
Follow up to r1667900: semtimedop() should be passed a relative timeout rather then absolute. semtimedop() takes a delta time, so accept what is given as the "time remaining" rr1790301 Use our "portable" versions Make clear this is a delta timeout locks: when pthread_mutex_timedlock() isn't available, fall back to an implementation based on pthread_cond_timedwait() when possible. Avoid a compiler warning by using system's errno. locks: follow up to r1790330. When no native timedlock is available, fall back to a common/generic spin sleep proc_mutex_spinsleep_timedacquire() based on the configured APR_USE_*_SERIALIZE trylock. Otherwise, choose the best timedlock mechanism in the following order: 1. PTHREAD if HAVE_PTHREAD_MUTEX_ROBUST && (HAVE_PTHREAD_MUTEX_TIMEDLOCK || HAVE_PTHREAD_CONDATTR_SETPSHARED) 2. SYSV if HAVE_SEMTIMEDOP 3. POSIX if HAVE_SEM_TIMEDWAIT 4. The one of APR_USE_*_SERIALIZE, hence possibly non-robust and/or spinning with the same robustness as the underlying apr_proc_mutex_trylock() call. apr_proc_mutex_timedlock() won't return ENOTIMPL anymore. locks: follow up to r1790330 and r1790436. unix/misc.c is not needed anymore since we use apr_proc_mutex_trylock() directly. locks: follow up to r1790330. No functional change, more helpers/macros to help identify struct proc_pthread_mutex_t members. locks: follow up to r1790330. Don't try to access proc_pthread_mutex_t's condvar if the mutex was _put[_ex]() and not _create()d, this is a real pthread_mutex_t. Submitted by: ylavic, jim, jim, jim, ylavic, ylavic, ylavic, ylavic, ylavic, ylavic git-svn-id: https://svn.apache.org/repos/asf/apr/apr/branches/1.6.x@1790474 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--configure.in5
-rw-r--r--locks/unix/misc.c193
-rw-r--r--locks/unix/proc_mutex.c479
-rw-r--r--locks/unix/thread_mutex.c67
-rw-r--r--test/testprocmutex.c27
5 files changed, 470 insertions, 301 deletions
diff --git a/configure.in b/configure.in
index cfd79e85b..29fd00d85 100644
--- a/configure.in
+++ b/configure.in
@@ -2297,6 +2297,11 @@ APR_IFALLYES(header:pthread.h define:PTHREAD_PROCESS_SHARED dnl
hasprocpthreadser="1", hasprocpthreadser="0")
APR_IFALLYES(header:OS.h func:create_sem, hasbeossem="1", hasbeossem="0")
+AC_CHECK_FUNCS(pthread_condattr_setpshared)
+APR_IFALLYES(header:pthread.h func:pthread_condattr_setpshared,
+ have_pthread_condattr_setpshared="1", have_pthread_condattr_setpshared="0")
+AC_SUBST(have_pthread_condattr_setpshared)
+
# See which lock mechanism we'll select by default on this system.
# The last APR_DECIDE to execute sets the default.
# At this stage, we match the ordering in Apache 1.3
diff --git a/locks/unix/misc.c b/locks/unix/misc.c
deleted file mode 100644
index d7018fc3a..000000000
--- a/locks/unix/misc.c
+++ /dev/null
@@ -1,193 +0,0 @@
-/* Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "apr_private.h"
-#include "apr_arch_thread_mutex.h"
-#define APR_WANT_MEMFUNC
-#include "apr_want.h"
-
-#if APR_HAS_THREADS
-#if APR_HAS_SYSVSEM_SERIALIZE
-#if !HAVE_SEMTIMEDOP
-#include <sys/sem.h>
-#endif
-#endif
-#define SLEEP_TIME_NS 10000000
-#define NANOSECS_PER_SEC 1000000000
-extern int errno;
-
-#ifndef HAVE_PTHREAD_MUTEX_TIMEDLOCK
-extern int pthread_mutex_timedlock(pthread_mutex_t * mutex,
- const struct timespec *abs_timeout);
-/*
- * A pthread_mutex_timedlock() impl for OSX/macOS, which lacks the
- * real thing.
- * NOTE: Unlike the real McCoy, won't return EOWNERDEAD, EDEADLK
- * or EOWNERDEAD
- */
-int pthread_mutex_timedlock(pthread_mutex_t * mutex,
- const struct timespec *abs_timeout)
-{
- int rv;
- struct timespec remaining, ts, tod;
- apr_time_t now;
-
- remaining = *abs_timeout;
- now = apr_time_now();
- tod.tv_sec = apr_time_sec(now);
- tod.tv_nsec = apr_time_usec(now) * 1000; /* nanoseconds */
-
- remaining.tv_sec -= tod.tv_sec;
- if (tod.tv_nsec <= remaining.tv_nsec) {
- remaining.tv_nsec -= tod.tv_nsec;
- }
- else {
- remaining.tv_sec--;
- remaining.tv_nsec =
- (NANOSECS_PER_SEC - (tod.tv_nsec - remaining.tv_nsec));
- }
- /* If we had a REALLY small timeout ;) */
- if (remaining.tv_sec < 0) {
- return ETIMEDOUT;
- }
- while ((rv = pthread_mutex_trylock(mutex)) == EBUSY) {
- ts.tv_sec = 0;
- ts.tv_nsec = (remaining.tv_sec > 0 ? SLEEP_TIME_NS :
- (remaining.tv_nsec <
- SLEEP_TIME_NS ? remaining.tv_nsec : SLEEP_TIME_NS));
- nanosleep(&ts, &ts);
- if (ts.tv_nsec <= remaining.tv_nsec) {
- remaining.tv_nsec -= ts.tv_nsec;
- }
- else {
- remaining.tv_sec--;
- remaining.tv_nsec =
- (NANOSECS_PER_SEC - (ts.tv_nsec - remaining.tv_nsec));
- }
- if (remaining.tv_sec < 0
- || (!remaining.tv_sec && remaining.tv_nsec <= SLEEP_TIME_NS)) {
- return ETIMEDOUT;
- }
- }
-
- return rv;
-}
-#endif /* HAVE_PTHREAD_MUTEX_TIMEDLOCK */
-
-#if APR_HAS_POSIXSEM_SERIALIZE
-#if !HAVE_SEM_TIMEDWAIT
-extern int sem_timedwait(sem_t * sem, const struct timespec *abs_timeout);
-/*
- * A sem_timedwait() impl for OSX/macOS, which lacks the
- * real thing.
- */
-int sem_timedwait(sem_t * sem, const struct timespec *abs_timeout)
-{
- int rv;
- struct timespec remaining, ts, tod;
- apr_time_t now;
-
- remaining = *abs_timeout;
- now = apr_time_now();
- tod.tv_sec = apr_time_sec(now);
- tod.tv_nsec = apr_time_usec(now) * 1000; /* nanoseconds */
-
- remaining.tv_sec -= tod.tv_sec;
- if (tod.tv_nsec <= remaining.tv_nsec) {
- remaining.tv_nsec -= tod.tv_nsec;
- }
- else {
- remaining.tv_sec--;
- remaining.tv_nsec =
- (NANOSECS_PER_SEC - (tod.tv_nsec - remaining.tv_nsec));
- }
- /* If we had a REALLY small timeout ;) */
- if (remaining.tv_sec < 0) {
- return ETIMEDOUT;
- }
- errno = 0;
- while (((rv = sem_trywait(sem)) != 0) && (errno == EAGAIN)) {
- ts.tv_sec = 0;
- ts.tv_nsec = (remaining.tv_sec > 0 ? SLEEP_TIME_NS :
- (remaining.tv_nsec <
- SLEEP_TIME_NS ? remaining.tv_nsec : SLEEP_TIME_NS));
- nanosleep(&ts, &ts);
- if (ts.tv_nsec <= remaining.tv_nsec) {
- remaining.tv_nsec -= ts.tv_nsec;
- }
- else {
- remaining.tv_sec--;
- remaining.tv_nsec =
- (NANOSECS_PER_SEC - (ts.tv_nsec - remaining.tv_nsec));
- }
- if (remaining.tv_sec < 0
- || (!remaining.tv_sec && remaining.tv_nsec <= SLEEP_TIME_NS)) {
- return ETIMEDOUT;
- }
- }
- return rv;
-}
-#endif /* HAVE_SEM_TIMEDWAIT */
-#endif /* APR_HAS_POSIXSEM_SERIALIZE */
-
-#if APR_HAS_SYSVSEM_SERIALIZE
-#if !HAVE_SEMTIMEDOP
-extern int semtimedop(int semid, struct sembuf *sops, unsigned nsops,
- const struct timespec *timeout);
-/*
- * A semtimedop() impl for OSX/macOS, which lacks the
- * real thing.
- */
-int semtimedop(int semid, struct sembuf *sops, unsigned nsops,
- const struct timespec *timeout)
-{
- int rv;
- struct timespec remaining, ts;
- struct sembuf proc_mutex_op_try;
-
- proc_mutex_op_try.sem_num = 0;
- proc_mutex_op_try.sem_op = -1;
- proc_mutex_op_try.sem_flg = SEM_UNDO | IPC_NOWAIT;
-
- remaining = *timeout;
- errno = 0;
- while (((rv = semop(semid, &proc_mutex_op_try, nsops)) != 0)
- && (errno == EAGAIN)) {
- ts.tv_sec = 0;
- ts.tv_nsec = (remaining.tv_sec > 0 ? SLEEP_TIME_NS :
- (remaining.tv_nsec <
- SLEEP_TIME_NS ? remaining.tv_nsec : SLEEP_TIME_NS));
- nanosleep(&ts, &ts);
- if (ts.tv_nsec <= remaining.tv_nsec) {
- remaining.tv_nsec -= ts.tv_nsec;
- }
- else {
- remaining.tv_sec--;
- remaining.tv_nsec =
- (NANOSECS_PER_SEC - (ts.tv_nsec - remaining.tv_nsec));
- }
- if (remaining.tv_sec < 0
- || (!remaining.tv_sec && remaining.tv_nsec <= SLEEP_TIME_NS)) {
- return ETIMEDOUT;
- }
- }
- return rv;
-}
-#endif /* HAVE_SEMTIMEDOP */
-#endif /* APR_HAS_SYSVSEM_SERIALIZE */
-
-
-#endif /* APR_HAS_THREADS */
diff --git a/locks/unix/proc_mutex.c b/locks/unix/proc_mutex.c
index c4ec910ee..3508b4f04 100644
--- a/locks/unix/proc_mutex.c
+++ b/locks/unix/proc_mutex.c
@@ -46,6 +46,56 @@ static apr_status_t proc_mutex_no_perms_set(apr_proc_mutex_t *mutex,
}
#endif
+#if APR_HAS_FCNTL_SERIALIZE \
+ || APR_HAS_FLOCK_SERIALIZE \
+ || (APR_HAS_SYSVSEM_SERIALIZE \
+ && !defined(HAVE_SEMTIMEDOP)) \
+ || (APR_HAS_POSIXSEM_SERIALIZE \
+ && !defined(HAVE_SEM_TIMEDWAIT)) \
+ || (APR_HAS_PROC_PTHREAD_SERIALIZE \
+ && !defined(HAVE_PTHREAD_MUTEX_TIMEDLOCK) \
+ && !defined(HAVE_PTHREAD_CONDATTR_SETPSHARED))
+static apr_status_t proc_mutex_spinsleep_timedacquire(apr_proc_mutex_t *mutex,
+ apr_time_t timeout,
+ int absolute)
+{
+ apr_status_t rv;
+ if (absolute) {
+ timeout -= apr_time_now();
+ if (timeout < 0) {
+ timeout = 0;
+ }
+ }
+ if (timeout < 0) {
+ rv = apr_proc_mutex_lock(mutex);
+ }
+ else {
+#define SLEEP_TIME apr_time_from_msec(10)
+ for (;;) {
+ rv = apr_proc_mutex_trylock(mutex);
+ if (!APR_STATUS_IS_EBUSY(rv)) {
+ if (rv == APR_SUCCESS) {
+ mutex->curr_locked = 1;
+ }
+ break;
+ }
+ if (!timeout) {
+ rv = APR_TIMEUP;
+ break;
+ }
+ if (timeout > SLEEP_TIME) {
+ apr_sleep(SLEEP_TIME);
+ timeout -= SLEEP_TIME;
+ }
+ else {
+ apr_sleep(timeout);
+ timeout = 0;
+ }
+ }
+ }
+ return rv;
+}
+#endif
#if APR_HAS_POSIXSEM_SERIALIZE
@@ -183,13 +233,11 @@ static apr_status_t proc_mutex_posix_tryacquire(apr_proc_mutex_t *mutex)
return APR_SUCCESS;
}
+#if defined(HAVE_SEM_TIMEDWAIT)
static apr_status_t proc_mutex_posix_timedacquire(apr_proc_mutex_t *mutex,
apr_time_t timeout,
int absolute)
{
-#if !HAVE_SEM_TIMEDWAIT
-extern int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
-#endif
if (timeout < 0) {
return proc_mutex_posix_acquire(mutex);
}
@@ -216,6 +264,7 @@ extern int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
mutex->curr_locked = 1;
return APR_SUCCESS;
}
+#endif
static apr_status_t proc_mutex_posix_release(apr_proc_mutex_t *mutex)
{
@@ -238,7 +287,11 @@ static const apr_proc_mutex_unix_lock_methods_t mutex_posixsem_methods =
proc_mutex_posix_create,
proc_mutex_posix_acquire,
proc_mutex_posix_tryacquire,
+#if defined(HAVE_SEM_TIMEDWAIT)
proc_mutex_posix_timedacquire,
+#else
+ proc_mutex_spinsleep_timedacquire,
+#endif
proc_mutex_posix_release,
proc_mutex_posix_cleanup,
proc_mutex_no_child_init,
@@ -337,28 +390,28 @@ static apr_status_t proc_mutex_sysv_tryacquire(apr_proc_mutex_t *mutex)
return APR_SUCCESS;
}
+#if defined(HAVE_SEMTIMEDOP)
static apr_status_t proc_mutex_sysv_timedacquire(apr_proc_mutex_t *mutex,
apr_time_t timeout,
int absolute)
{
-#if !HAVE_SEMTIMEDOP
-extern int semtimedop(int semid, struct sembuf *sops, unsigned nsops,
- const struct timespec *timeout);
-#endif
if (timeout < 0) {
return proc_mutex_sysv_acquire(mutex);
}
else {
int rc;
- struct timespec abstime;
- if (!absolute) {
- timeout += apr_time_now();
+ struct timespec reltime;
+ if (absolute) {
+ timeout -= apr_time_now();
+ if (timeout < 0) {
+ return proc_mutex_sysv_tryacquire(mutex);
+ }
}
- abstime.tv_sec = apr_time_sec(timeout);
- abstime.tv_nsec = apr_time_usec(timeout) * 1000; /* nanoseconds */
+ reltime.tv_sec = apr_time_sec(timeout);
+ reltime.tv_nsec = apr_time_usec(timeout) * 1000; /* nanoseconds */
do {
rc = semtimedop(mutex->os.crossproc, &proc_mutex_op_on, 1,
- &abstime);
+ &reltime);
} while (rc < 0 && errno == EINTR);
if (rc < 0) {
if (errno == EAGAIN) {
@@ -370,6 +423,7 @@ extern int semtimedop(int semid, struct sembuf *sops, unsigned nsops,
mutex->curr_locked = 1;
return APR_SUCCESS;
}
+#endif
static apr_status_t proc_mutex_sysv_release(apr_proc_mutex_t *mutex)
{
@@ -413,7 +467,11 @@ static const apr_proc_mutex_unix_lock_methods_t mutex_sysv_methods =
proc_mutex_sysv_create,
proc_mutex_sysv_acquire,
proc_mutex_sysv_tryacquire,
+#if defined(HAVE_SEMTIMEDOP)
proc_mutex_sysv_timedacquire,
+#else
+ proc_mutex_spinsleep_timedacquire,
+#endif
proc_mutex_sysv_release,
proc_mutex_sysv_cleanup,
proc_mutex_no_child_init,
@@ -426,6 +484,12 @@ static const apr_proc_mutex_unix_lock_methods_t mutex_sysv_methods =
#if APR_HAS_PROC_PTHREAD_SERIALIZE
+#ifndef APR_USE_PROC_PTHREAD_MUTEX_COND
+#define APR_USE_PROC_PTHREAD_MUTEX_COND \
+ (defined(HAVE_PTHREAD_CONDATTR_SETPSHARED) \
+ && !defined(HAVE_PTHREAD_MUTEX_TIMEDLOCK))
+#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
@@ -436,12 +500,31 @@ static const apr_proc_mutex_unix_lock_methods_t mutex_sysv_methods =
* destroy it.
*/
typedef struct {
+#define proc_pthread_cast(m) \
+ ((proc_pthread_mutex_t *)(m)->os.pthread_interproc)
pthread_mutex_t mutex;
+#define proc_pthread_mutex(m) \
+ (proc_pthread_cast(m)->mutex)
+#if APR_USE_PROC_PTHREAD_MUTEX_COND
+ pthread_cond_t cond;
+#define proc_pthread_mutex_cond(m) \
+ (proc_pthread_cast(m)->cond)
+ apr_int32_t cond_locked;
+#define proc_pthread_mutex_cond_locked(m) \
+ ((m)->pthread_refcounting ? proc_pthread_cast(m)->cond_locked : -1)
+ apr_uint32_t cond_num_waiters;
+#define proc_pthread_mutex_cond_num_waiters(m) \
+ (proc_pthread_cast(m)->cond_num_waiters)
+#endif /* APR_USE_PROC_PTHREAD_MUTEX_COND */
apr_uint32_t refcount;
+#define proc_pthread_mutex_refcount(m) \
+ (proc_pthread_cast(m)->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)
{
@@ -465,8 +548,14 @@ static apr_status_t proc_pthread_mutex_unref(void *mutex_)
apr_proc_mutex_t *mutex=mutex_;
apr_status_t rv;
+#if APR_USE_PROC_PTHREAD_MUTEX_COND
+ if (proc_pthread_mutex_cond_locked(mutex) != -1) {
+ mutex->curr_locked = 0;
+ }
+ else
+#endif /* APR_USE_PROC_PTHREAD_MUTEX_COND */
if (mutex->curr_locked == 1) {
- if ((rv = pthread_mutex_unlock(mutex->os.pthread_interproc))) {
+ if ((rv = pthread_mutex_unlock(&proc_pthread_mutex(mutex)))) {
#ifdef HAVE_ZOS_PTHREADS
rv = errno;
#endif
@@ -474,7 +563,17 @@ static apr_status_t proc_pthread_mutex_unref(void *mutex_)
}
}
if (!proc_pthread_mutex_dec(mutex)) {
- if ((rv = pthread_mutex_destroy(mutex->os.pthread_interproc))) {
+#if APR_USE_PROC_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 /* APR_USE_PROC_PTHREAD_MUTEX_COND */
+
+ if ((rv = pthread_mutex_destroy(&proc_pthread_mutex(mutex)))) {
#ifdef HAVE_ZOS_PTHREADS
rv = errno;
#endif
@@ -526,6 +625,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 */
+#if APR_USE_PROC_PTHREAD_MUTEX_COND
+ proc_pthread_mutex_cond_locked(new_mutex) = -1;
+#endif
if ((rv = pthread_mutexattr_init(&mattr))) {
#ifdef HAVE_ZOS_PTHREADS
@@ -563,7 +665,7 @@ static apr_status_t proc_mutex_pthread_create(apr_proc_mutex_t *new_mutex,
}
#endif /* HAVE_PTHREAD_MUTEX_ROBUST */
- if ((rv = pthread_mutex_init(new_mutex->os.pthread_interproc, &mattr))) {
+ if ((rv = pthread_mutex_init(&proc_pthread_mutex(new_mutex), &mattr))) {
#ifdef HAVE_ZOS_PTHREADS
rv = errno;
#endif
@@ -604,105 +706,200 @@ 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)
{
- apr_status_t rv;
-
- if ((rv = pthread_mutex_trylock(mutex->os.pthread_interproc))) {
-#ifdef HAVE_ZOS_PTHREADS
- 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);
- }
- else
-#endif
- return rv;
- }
- mutex->curr_locked = 1;
- return APR_SUCCESS;
+ apr_status_t rv = proc_mutex_pthread_timedacquire(mutex, 0, 0);
+ return (rv == APR_TIMEUP) ? APR_EBUSY : 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);
+#if !APR_USE_PROC_PTHREAD_MUTEX_COND && !defined(HAVE_PTHREAD_MUTEX_TIMEDLOCK)
+ return proc_mutex_spinsleep_timedacquire(mutex, timeout, absolute);
+#else
+ apr_status_t rv;
+
+#if APR_USE_PROC_PTHREAD_MUTEX_COND
+ if (proc_pthread_mutex_cond_locked(mutex) != -1) {
+ if ((rv = pthread_mutex_lock(&proc_pthread_mutex(mutex)))) {
+#ifdef HAVE_ZOS_PTHREADS
+ rv = errno;
#endif
- if (timeout < 0) {
- return proc_mutex_pthread_acquire(mutex);
- }
- else {
- apr_status_t rv;
- struct timespec abstime;
+#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(&proc_pthread_mutex(mutex));
+ }
+ else
+#endif
+ return rv;
+ }
- if (!absolute) {
- timeout += apr_time_now();
+ if (!proc_pthread_mutex_cond_locked(mutex)) {
+ proc_pthread_mutex_cond_locked(mutex) = 1;
+ }
+ else if (!timeout) {
+ rv = APR_TIMEUP;
+ }
+ else {
+ proc_pthread_mutex_cond_num_waiters(mutex)++;
+ if (timeout < 0) {
+ rv = pthread_cond_wait(&proc_pthread_mutex_cond(mutex),
+ &proc_pthread_mutex(mutex));
+#ifdef HAVE_ZOS_PTHREADS
+ if (rv) {
+ rv = errno;
+ }
+#endif
+ }
+ 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),
+ &proc_pthread_mutex(mutex),
+ &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(&proc_pthread_mutex(mutex));
+ return rv;
}
- abstime.tv_sec = apr_time_sec(timeout);
- abstime.tv_nsec = apr_time_usec(timeout) * 1000; /* nanoseconds */
- if ((rv = pthread_mutex_timedlock(mutex->os.pthread_interproc,
- &abstime))) {
-#ifdef HAVE_ZOS_PTHREADS
+ rv = pthread_mutex_unlock(&proc_pthread_mutex(mutex));
+ if (rv) {
+#ifdef HAVE_ZOS_PTHREADS
rv = errno;
#endif
- if (rv == ETIMEDOUT) {
- return APR_TIMEUP;
+ return rv;
+ }
+ }
+ else
+#endif /* APR_USE_PROC_PTHREAD_MUTEX_COND */
+ {
+ if (timeout < 0) {
+ rv = pthread_mutex_lock(&proc_pthread_mutex(mutex));
+ if (rv) {
+#ifdef HAVE_ZOS_PTHREADS
+ rv = errno;
+#endif
+ }
+ }
+ else if (!timeout) {
+ rv = pthread_mutex_trylock(&proc_pthread_mutex(mutex));
+ if (rv) {
+#ifdef HAVE_ZOS_PTHREADS
+ rv = errno;
+#endif
+ if (rv == EBUSY) {
+ return APR_TIMEUP;
+ }
+ }
+ }
+ 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_mutex_timedlock(&proc_pthread_mutex(mutex), &abstime);
+ if (rv) {
+#ifdef HAVE_ZOS_PTHREADS
+ rv = errno;
+#endif
+ if (rv == ETIMEDOUT) {
+ return APR_TIMEUP;
+ }
}
+ }
+ 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);
+ pthread_mutex_consistent_np(&proc_pthread_mutex(mutex));
}
else
#endif
return rv;
}
}
+
mutex->curr_locked = 1;
return APR_SUCCESS;
+#endif
}
static apr_status_t proc_mutex_pthread_release(apr_proc_mutex_t *mutex)
{
apr_status_t rv;
+#if APR_USE_PROC_PTHREAD_MUTEX_COND
+ if (proc_pthread_mutex_cond_locked(mutex) != -1) {
+ if ((rv = pthread_mutex_lock(&proc_pthread_mutex(mutex)))) {
+#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(&proc_pthread_mutex(mutex));
+ }
+ 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(&proc_pthread_mutex(mutex));
+ return rv;
+ }
+ }
+#endif /* APR_USE_PROC_PTHREAD_MUTEX_COND */
+
mutex->curr_locked = 0;
- if ((rv = pthread_mutex_unlock(mutex->os.pthread_interproc))) {
+ if ((rv = pthread_mutex_unlock(&proc_pthread_mutex(mutex)))) {
#ifdef HAVE_ZOS_PTHREADS
rv = errno;
#endif
return rv;
}
+
return APR_SUCCESS;
}
@@ -721,6 +918,69 @@ static const apr_proc_mutex_unix_lock_methods_t mutex_proc_pthread_methods =
"pthread"
};
+#if APR_USE_PROC_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_PROC_PTHREAD,
+ "pthread"
+};
+#endif
+
#endif
#if APR_HAS_FCNTL_SERIALIZE
@@ -836,13 +1096,6 @@ static apr_status_t proc_mutex_fcntl_tryacquire(apr_proc_mutex_t *mutex)
return APR_SUCCESS;
}
-static apr_status_t proc_mutex_fcntl_timedacquire(apr_proc_mutex_t *mutex,
- apr_time_t timeout,
- int absolute)
-{
- return APR_ENOTIMPL;
-}
-
static apr_status_t proc_mutex_fcntl_release(apr_proc_mutex_t *mutex)
{
int rc;
@@ -883,7 +1136,7 @@ static const apr_proc_mutex_unix_lock_methods_t mutex_fcntl_methods =
proc_mutex_fcntl_create,
proc_mutex_fcntl_acquire,
proc_mutex_fcntl_tryacquire,
- proc_mutex_fcntl_timedacquire,
+ proc_mutex_spinsleep_timedacquire,
proc_mutex_fcntl_release,
proc_mutex_fcntl_cleanup,
proc_mutex_no_child_init,
@@ -987,13 +1240,6 @@ static apr_status_t proc_mutex_flock_tryacquire(apr_proc_mutex_t *mutex)
return APR_SUCCESS;
}
-static apr_status_t proc_mutex_flock_timedacquire(apr_proc_mutex_t *mutex,
- apr_time_t timeout,
- int absolute)
-{
- return APR_ENOTIMPL;
-}
-
static apr_status_t proc_mutex_flock_release(apr_proc_mutex_t *mutex)
{
int rc;
@@ -1064,7 +1310,7 @@ static const apr_proc_mutex_unix_lock_methods_t mutex_flock_methods =
proc_mutex_flock_create,
proc_mutex_flock_acquire,
proc_mutex_flock_tryacquire,
- proc_mutex_flock_timedacquire,
+ proc_mutex_spinsleep_timedacquire,
proc_mutex_flock_release,
proc_mutex_flock_cleanup,
proc_mutex_flock_child_init,
@@ -1171,6 +1417,43 @@ static apr_status_t proc_mutex_choose_method(apr_proc_mutex_t *new_mutex,
return APR_ENOTIMPL;
#endif
break;
+ case APR_LOCK_DEFAULT_TIMED:
+#if APR_HAS_PROC_PTHREAD_SERIALIZE \
+ && (APR_USE_PROC_PTHREAD_MUTEX_COND \
+ || defined(HAVE_PTHREAD_MUTEX_TIMEDLOCK)) \
+ && defined(HAVE_PTHREAD_MUTEX_ROBUST)
+#if APR_USE_PROC_PTHREAD_MUTEX_COND
+ new_mutex->meth = &mutex_proc_pthread_cond_methods;
+#else
+ new_mutex->meth = &mutex_proc_pthread_methods;
+#endif
+ if (ospmutex) {
+ if (ospmutex->pthread_interproc == NULL) {
+ return APR_EINVAL;
+ }
+ new_mutex->os.pthread_interproc = ospmutex->pthread_interproc;
+ }
+ break;
+#elif APR_HAS_SYSVSEM_SERIALIZE && defined(HAVE_SEMTIMEDOP)
+ new_mutex->meth = &mutex_sysv_methods;
+ if (ospmutex) {
+ if (ospmutex->crossproc == -1) {
+ return APR_EINVAL;
+ }
+ new_mutex->os.crossproc = ospmutex->crossproc;
+ }
+ break;
+#elif APR_HAS_POSIXSEM_SERIALIZE && defined(HAVE_SEM_TIMEDWAIT)
+ new_mutex->meth = &mutex_posixsem_methods;
+ if (ospmutex) {
+ if (ospmutex->psem_interproc == NULL) {
+ return APR_EINVAL;
+ }
+ new_mutex->os.psem_interproc = ospmutex->psem_interproc;
+ }
+ break;
+#endif
+ /* fall trough */
case APR_LOCK_DEFAULT:
#if APR_USE_FLOCK_SERIALIZE
new_mutex->meth = &mutex_flock_methods;
@@ -1216,18 +1499,6 @@ static apr_status_t proc_mutex_choose_method(apr_proc_mutex_t *new_mutex,
return APR_ENOTIMPL;
#endif
break;
- case APR_LOCK_DEFAULT_TIMED:
-#if APR_HAS_PROC_PTHREAD_SERIALIZE \
- && defined(HAVE_PTHREAD_MUTEX_ROBUST)
- new_mutex->meth = &mutex_proc_pthread_methods;
-#elif APR_HAS_SYSVSEM_SERIALIZE
- new_mutex->meth = &mutex_sysv_methods;
-#elif APR_HAS_POSIXSEM_SERIALIZE
- new_mutex->meth = &mutex_posixsem_methods;
-#else
- return APR_ENOTIMPL;
-#endif
- break;
default:
return APR_ENOTIMPL;
}
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;
}
diff --git a/test/testprocmutex.c b/test/testprocmutex.c
index 599d58520..3aff25b88 100644
--- a/test/testprocmutex.c
+++ b/test/testprocmutex.c
@@ -20,6 +20,7 @@
#include "apr_proc_mutex.h"
#include "apr_errno.h"
#include "apr_general.h"
+#include "apr_strings.h"
#include "apr_getopt.h"
#include <stdio.h>
#include <stdlib.h>
@@ -155,6 +156,19 @@ static void test_exclusive(abts_case *tc, const char *lockname,
else {
APR_ASSERT_SUCCESS(tc, "check for trylock", rv);
+ for (n = 0; n < 2; n++) {
+ rv = apr_proc_mutex_trylock(proc_lock);
+ /* Some mech (eg. flock or fcntl) may succeed when the
+ * lock is re-acquired in the same process.
+ */
+ if (rv != APR_SUCCESS) {
+ ABTS_ASSERT(tc,
+ apr_psprintf(p, "%s_trylock() should be busy => %pm",
+ mech->name, &rv),
+ APR_STATUS_IS_EBUSY(rv));
+ }
+ }
+
rv = apr_proc_mutex_unlock(proc_lock);
APR_ASSERT_SUCCESS(tc, "unlock after trylock check", rv);
@@ -179,6 +193,19 @@ static void test_exclusive(abts_case *tc, const char *lockname,
else {
APR_ASSERT_SUCCESS(tc, "check for timedlock", rv);
+ for (n = 0; n < 2; n++) {
+ rv = apr_proc_mutex_timedlock(proc_lock, 1, 0);
+ /* Some mech (eg. flock or fcntl) may succeed when the
+ * lock is re-acquired in the same process.
+ */
+ if (rv != APR_SUCCESS) {
+ ABTS_ASSERT(tc,
+ apr_psprintf(p, "%s_timedlock() should time out => %pm",
+ mech->name, &rv),
+ APR_STATUS_IS_TIMEUP(rv));
+ }
+ }
+
rv = apr_proc_mutex_unlock(proc_lock);
APR_ASSERT_SUCCESS(tc, "unlock after timedlock check", rv);