diff options
author | Yann Ylavic <ylavic@apache.org> | 2016-03-05 01:40:58 +0000 |
---|---|---|
committer | Yann Ylavic <ylavic@apache.org> | 2016-03-05 01:40:58 +0000 |
commit | e547c8577920802132994329ca50a554571fd308 (patch) | |
tree | 893502b6a98b9a3eb26821534f45db589cf0c67e /locks | |
parent | 878278c3c98ab6c43ed645fef25d116dde16f22c (diff) | |
download | apr-e547c8577920802132994329ca50a554571fd308.tar.gz |
Merge r930508, r1667900, r1667901, r1667903, r1667962, r1669077, r1671292, r1732582 from trunk:
OS/2: Add an implementation of condition variables, derived from the Win32
implementation.
locks: introduce apr_{thread,proc,global}_mutex_timedlock().
For proc mutexes, the new mechanism APR_LOCK_DEFAULT_TIMED usable at creation time
allows for the best mechanism to be elected (unixes: 1 to 3, or specific: 4 to 7):
1. PROC_PTHREAD if pthread_mutex_timedlock() and pthread_mutex_set_robust_np()
are both available,
2. SYSV if semtimedop() is availale,
3. POSIXSEM if sem_timedwait() is available,
4. BeOS' acquire_sem_etc() if available,
5. NetWare falls back to apr_thread_mutex_timedlock() as for others functions,
6. OS2's DosRequestMutexSem(),
7. Windows' WaitForSingleObject().
Otherwise (like when fcntl and flock only are availble, if that's ever possible),
APR_ENOTIMPL is returned.
For thread mutexes, the new flag APR_THREAD_MUTEX_TIMED, usable at create()
time still, allows to switch to an implementation using a condition variable
and apr_thread_cond_timedwait() when if no native mechanism is available (eg.
NetWare, pthreads but without pthread_mutex_timedlock() available).
On windows, this initializes a WaitForSingleObject()able handle (Mutex) instead
of the fastest (but not timeout-able) CRITICAL_SECTION used by default.
All apr_{thread,proc,global}_mutex_timedlock() functions can take a relative or
absolute time, thanks to the last (boolean) argument.
Test suite updated accordingly.
Follow up to r1667900: revert spurious change on test/abts_tests.h.
Follow up to r1667900: fix comments.
Follow up to r1667900: handle negative (infinite) timeout in mutex/cond timedlock/timedwait.
locks: follow up to r1667900.
In apr_global_mutex_timedlock(), we can avoid converting from relative to
absolute time if thread locking is not needed.
make internal function static to avoid a warning
Follow up to r1667900: Avoid a circular reference (PR 59068).
Submitted by: bjh, ylavic, ylavic, ylavic, ylavic, ylavic, trawick, ylavic
Reviewed/backported by: ylavic
git-svn-id: https://svn.apache.org/repos/asf/apr/apr/branches/1.6.x@1733684 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'locks')
-rw-r--r-- | locks/beos/proc_mutex.c | 82 | ||||
-rw-r--r-- | locks/beos/thread_cond.c | 2 | ||||
-rw-r--r-- | locks/beos/thread_mutex.c | 99 | ||||
-rw-r--r-- | locks/netware/proc_mutex.c | 26 | ||||
-rw-r--r-- | locks/netware/thread_cond.c | 19 | ||||
-rw-r--r-- | locks/netware/thread_mutex.c | 109 | ||||
-rw-r--r-- | locks/os2/proc_mutex.c | 38 | ||||
-rw-r--r-- | locks/os2/thread_cond.c | 150 | ||||
-rw-r--r-- | locks/os2/thread_mutex.c | 30 | ||||
-rw-r--r-- | locks/unix/global_mutex.c | 34 | ||||
-rw-r--r-- | locks/unix/proc_mutex.c | 155 | ||||
-rw-r--r-- | locks/unix/thread_cond.c | 32 | ||||
-rw-r--r-- | locks/unix/thread_mutex.c | 209 | ||||
-rw-r--r-- | locks/win32/proc_mutex.c | 31 | ||||
-rw-r--r-- | locks/win32/thread_cond.c | 13 | ||||
-rw-r--r-- | locks/win32/thread_mutex.c | 44 |
16 files changed, 995 insertions, 78 deletions
diff --git a/locks/beos/proc_mutex.c b/locks/beos/proc_mutex.c index a02668add..4408df094 100644 --- a/locks/beos/proc_mutex.c +++ b/locks/beos/proc_mutex.c @@ -27,13 +27,13 @@ static apr_status_t _proc_mutex_cleanup(void * data) apr_proc_mutex_t *lock = (apr_proc_mutex_t*)data; if (lock->LockCount != 0) { /* we're still locked... */ - while (atomic_add(&lock->LockCount , -1) > 1){ - /* OK we had more than one person waiting on the lock so - * the sem is also locked. Release it until we have no more - * locks left. - */ + while (atomic_add(&lock->LockCount , -1) > 1){ + /* OK we had more than one person waiting on the lock so + * the sem is also locked. Release it until we have no more + * locks left. + */ release_sem (lock->Lock); - } + } } delete_sem(lock->Lock); return APR_SUCCESS; @@ -47,7 +47,7 @@ APR_DECLARE(apr_status_t) apr_proc_mutex_create(apr_proc_mutex_t **mutex, apr_proc_mutex_t *new; apr_status_t stat = APR_SUCCESS; - if (mech != APR_LOCK_DEFAULT) { + if (mech != APR_LOCK_DEFAULT && mech != APR_LOCK_DEFAULT_TIMED) { return APR_ENOTIMPL; } @@ -82,25 +82,77 @@ APR_DECLARE(apr_status_t) apr_proc_mutex_lock(apr_proc_mutex_t *mutex) { int32 stat; - if (atomic_add(&mutex->LockCount, 1) > 0) { - if ((stat = acquire_sem(mutex->Lock)) < B_NO_ERROR) { - atomic_add(&mutex->LockCount, -1); - return stat; - } - } + if (atomic_add(&mutex->LockCount, 1) > 0) { + if ((stat = acquire_sem(mutex->Lock)) < B_NO_ERROR) { + atomic_add(&mutex->LockCount, -1); + return stat; + } + } return APR_SUCCESS; } APR_DECLARE(apr_status_t) apr_proc_mutex_trylock(apr_proc_mutex_t *mutex) { - return APR_ENOTIMPL; + int32 stat; + + if (atomic_add(&mutex->LockCount, 1) > 0) { + stat = acquire_sem_etc(mutex->Lock, 1, 0, 0); + if (stat < B_NO_ERROR) { + atomic_add(&mutex->LockCount, -1); + if (stat == B_WOULD_BLOCK) { + stat = APR_EBUSY; + } + return stat; + } + } + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_proc_mutex_timedlock(apr_proc_mutex_t *mutex, + apr_time_t timeout, + int absolute) +{ + int32 stat; + + if (atomic_add(&mutex->LockCount, 1) > 0) { + if (timeout < 0) { + stat = acquire_sem(mutex->Lock); + } + else { + int flag = 0; + if (timeout > 0) { + if (absolute) { + apr_time_t now = apr_time_now(); + if (timeout > now) { + timeout -= now; + } + else { + timeout = 0; + } + flag = B_ABSOLUTE_TIMEOUT; + } + else { + flag = B_RELATIVE_TIMEOUT; + } + } + stat = acquire_sem_etc(mutex->Lock, 1, flag, timeout); + } + if (stat < B_NO_ERROR) { + atomic_add(&mutex->LockCount, -1); + if (stat == B_TIMED_OUT) { + stat = APR_TIMEUP; + } + return stat; + } + } + return APR_SUCCESS; } APR_DECLARE(apr_status_t) apr_proc_mutex_unlock(apr_proc_mutex_t *mutex) { int32 stat; - if (atomic_add(&mutex->LockCount, -1) > 1) { + if (atomic_add(&mutex->LockCount, -1) > 1) { if ((stat = release_sem(mutex->Lock)) < B_NO_ERROR) { atomic_add(&mutex->LockCount, 1); return stat; diff --git a/locks/beos/thread_cond.c b/locks/beos/thread_cond.c index 44189d908..a0978c008 100644 --- a/locks/beos/thread_cond.c +++ b/locks/beos/thread_cond.c @@ -81,7 +81,7 @@ APR_DECLARE(apr_status_t) apr_thread_cond_create(apr_thread_cond_t **cond, static apr_status_t do_wait(apr_thread_cond_t *cond, apr_thread_mutex_t *mutex, - int timeout) + apr_interval_time_t timeout) { struct waiter_t *wait; thread_id cth = find_thread(NULL); diff --git a/locks/beos/thread_mutex.c b/locks/beos/thread_mutex.c index b87f76606..2fa1bc70b 100644 --- a/locks/beos/thread_mutex.c +++ b/locks/beos/thread_mutex.c @@ -27,13 +27,13 @@ static apr_status_t _thread_mutex_cleanup(void * data) apr_thread_mutex_t *lock = (apr_thread_mutex_t*)data; if (lock->LockCount != 0) { /* we're still locked... */ - while (atomic_add(&lock->LockCount , -1) > 1){ - /* OK we had more than one person waiting on the lock so - * the sem is also locked. Release it until we have no more - * locks left. - */ + while (atomic_add(&lock->LockCount , -1) > 1){ + /* OK we had more than one person waiting on the lock so + * the sem is also locked. Release it until we have no more + * locks left. + */ release_sem (lock->Lock); - } + } } delete_sem(lock->Lock); return APR_SUCCESS; @@ -91,13 +91,13 @@ APR_DECLARE(apr_status_t) apr_thread_mutex_lock(apr_thread_mutex_t *mutex) return APR_SUCCESS; } - if (atomic_add(&mutex->LockCount, 1) > 0) { - if ((stat = acquire_sem(mutex->Lock)) < B_NO_ERROR) { + if (atomic_add(&mutex->LockCount, 1) > 0) { + if ((stat = acquire_sem(mutex->Lock)) < B_NO_ERROR) { /* Oh dear, acquire_sem failed!! */ - atomic_add(&mutex->LockCount, -1); - return stat; - } - } + atomic_add(&mutex->LockCount, -1); + return stat; + } + } mutex->owner = me; mutex->owner_ref = 1; @@ -107,7 +107,78 @@ APR_DECLARE(apr_status_t) apr_thread_mutex_lock(apr_thread_mutex_t *mutex) APR_DECLARE(apr_status_t) apr_thread_mutex_trylock(apr_thread_mutex_t *mutex) { - return APR_ENOTIMPL; + int32 stat; + thread_id me = find_thread(NULL); + + if (mutex->nested && mutex->owner == me) { + mutex->owner_ref++; + return APR_SUCCESS; + } + + if (atomic_add(&mutex->LockCount, 1) > 0) { + if ((stat = acquire_sem_etc(mutex->Lock, 1, 0, 0)) < B_NO_ERROR) { + atomic_add(&mutex->LockCount, -1); + if (stat == B_WOULD_BLOCK) { + stat = APR_EBUSY; + } + return stat; + } + } + + mutex->owner = me; + mutex->owner_ref = 1; + + return APR_SUCCESS; +} + +APR_DECLARE(apr_status_t) apr_thread_mutex_timedlock(apr_thread_mutex_t *mutex, + apr_time_t timeout, + int absolute) +{ + int32 stat; + thread_id me = find_thread(NULL); + + if (mutex->nested && mutex->owner == me) { + mutex->owner_ref++; + return APR_SUCCESS; + } + + if (atomic_add(&mutex->LockCount, 1) > 0) { + if (timeout < 0) { + stat = acquire_sem(mutex->Lock); + } + else { + int flag = 0; + if (timeout > 0) { + if (absolute) { + apr_time_t now = apr_time_now(); + if (timeout > now) { + timeout -= now; + } + else { + timeout = 0; + } + flag = B_ABSOLUTE_TIMEOUT; + } + else { + flag = B_RELATIVE_TIMEOUT; + } + } + stat = acquire_sem_etc(mutex->Lock, 1, flag, timeout); + } + if (stat < B_NO_ERROR) { + atomic_add(&mutex->LockCount, -1); + if (stat == B_TIMED_OUT) { + stat = APR_TIMEUP; + } + return stat; + } + } + + mutex->owner = me; + mutex->owner_ref = 1; + + return APR_SUCCESS; } APR_DECLARE(apr_status_t) apr_thread_mutex_unlock(apr_thread_mutex_t *mutex) @@ -120,7 +191,7 @@ APR_DECLARE(apr_status_t) apr_thread_mutex_unlock(apr_thread_mutex_t *mutex) return APR_SUCCESS; } - if (atomic_add(&mutex->LockCount, -1) > 1) { + if (atomic_add(&mutex->LockCount, -1) > 1) { if ((stat = release_sem(mutex->Lock)) < B_NO_ERROR) { atomic_add(&mutex->LockCount, 1); return stat; diff --git a/locks/netware/proc_mutex.c b/locks/netware/proc_mutex.c index 097914645..4217b1cf0 100644 --- a/locks/netware/proc_mutex.c +++ b/locks/netware/proc_mutex.c @@ -26,15 +26,24 @@ APR_DECLARE(apr_status_t) apr_proc_mutex_create(apr_proc_mutex_t **mutex, apr_pool_t *pool) { apr_status_t ret; - apr_proc_mutex_t *new_mutex = NULL; + apr_proc_mutex_t *new_mutex; + unsigned int flags = APR_THREAD_MUTEX_DEFAULT; + + *mutex = NULL; + if (mech == APR_LOCK_DEFAULT_TIMED) { + flags |= APR_THREAD_MUTEX_TIMED; + } + else if (mech != APR_LOCK_DEFAULT) { + return APR_ENOTIMPL; + } + new_mutex = (apr_proc_mutex_t *)apr_pcalloc(pool, sizeof(apr_proc_mutex_t)); - - if(new_mutex ==NULL) { + if (new_mutex == NULL) { return APR_ENOMEM; } new_mutex->pool = pool; - ret = apr_thread_mutex_create(&(new_mutex->mutex), APR_THREAD_MUTEX_DEFAULT, pool); + ret = apr_thread_mutex_create(&(new_mutex->mutex), flags, pool); if (ret == APR_SUCCESS) *mutex = new_mutex; @@ -63,6 +72,15 @@ APR_DECLARE(apr_status_t) apr_proc_mutex_trylock(apr_proc_mutex_t *mutex) return APR_ENOLOCK; } +APR_DECLARE(apr_status_t) apr_proc_mutex_timedlock(apr_thread_mutex_t *mutex, + apr_time_t timeout, + int absolute) +{ + if (mutex) + return apr_thread_mutex_timedlock(mutex->mutex, timeout, absolute); + return APR_ENOLOCK; +} + APR_DECLARE(apr_status_t) apr_proc_mutex_unlock(apr_proc_mutex_t *mutex) { if (mutex) diff --git a/locks/netware/thread_cond.c b/locks/netware/thread_cond.c index dcb21edc9..da1162bc2 100644 --- a/locks/netware/thread_cond.c +++ b/locks/netware/thread_cond.c @@ -66,10 +66,21 @@ APR_DECLARE(apr_status_t) apr_thread_cond_wait(apr_thread_cond_t *cond, APR_DECLARE(apr_status_t) apr_thread_cond_timedwait(apr_thread_cond_t *cond, apr_thread_mutex_t *mutex, - apr_interval_time_t timeout){ - if (NXCondTimedWait(cond->cond, mutex->mutex, - (timeout*1000)/NXGetSystemTick()) == NX_ETIMEDOUT) { - return APR_TIMEUP; + apr_interval_time_t timeout) +{ + int rc; + if (timeout < 0) { + rc = NXCondWait(cond->cond, mutex->mutex); + } + else { + timeout = timeout * 1000 / XGetSystemTick(); + rc = NXCondTimedWait(cond->cond, mutex->mutex, timeout); + if (rc == NX_ETIMEDOUT) { + return APR_TIMEUP; + } + } + if (rc != 0) { + return APR_EINTR; } return APR_SUCCESS; } diff --git a/locks/netware/thread_mutex.c b/locks/netware/thread_mutex.c index 98bf33bd2..a11ad8345 100644 --- a/locks/netware/thread_mutex.c +++ b/locks/netware/thread_mutex.c @@ -19,6 +19,7 @@ #include "apr_general.h" #include "apr_strings.h" #include "apr_arch_thread_mutex.h" +#include "apr_thread_cond.h" #include "apr_portable.h" static apr_status_t thread_mutex_cleanup(void *data) @@ -41,8 +42,8 @@ APR_DECLARE(apr_status_t) apr_thread_mutex_create(apr_thread_mutex_t **mutex, return APR_ENOTIMPL; } new_mutex = (apr_thread_mutex_t *)apr_pcalloc(pool, sizeof(apr_thread_mutex_t)); - - if(new_mutex ==NULL) { + + if (new_mutex == NULL) { return APR_ENOMEM; } new_mutex->pool = pool; @@ -52,6 +53,14 @@ APR_DECLARE(apr_status_t) apr_thread_mutex_create(apr_thread_mutex_t **mutex, if(new_mutex->mutex == NULL) return APR_ENOMEM; + if (flags & APR_THREAD_MUTEX_TIMED) { + apr_status_t rv = apr_thread_cond_create(&new_mutex->cond, pool); + if (rv != SUCCESS) { + NXMutexFree(new_mutex->mutex); + return rv; + } + } + apr_pool_cleanup_register(new_mutex->pool, new_mutex, (void*)thread_mutex_cleanup, apr_pool_cleanup_null); @@ -61,29 +70,117 @@ APR_DECLARE(apr_status_t) apr_thread_mutex_create(apr_thread_mutex_t **mutex, APR_DECLARE(apr_status_t) apr_thread_mutex_lock(apr_thread_mutex_t *mutex) { + if (mutex->cond) { + apr_status_t rv; + NXLock(mutex->mutex); + if (mutex->locked) { + mutex->num_waiters++; + rv = apr_thread_cond_wait(mutex->cond, mutex); + mutex->num_waiters--; + } + else { + mutex->locked = 1; + rv = APR_SUCCESS; + } + NXUnlock(mutex->mutex); + return rv; + } + NXLock(mutex->mutex); return APR_SUCCESS; } APR_DECLARE(apr_status_t) apr_thread_mutex_trylock(apr_thread_mutex_t *mutex) { + if (mutex->cond) { + apr_status_t rv; + NXLock(mutex->mutex); + if (mutex->locked) { + rv = APR_EBUSY; + } + else { + mutex->locked = 1; + rv = APR_SUCCESS; + } + NXUnlock(mutex->mutex); + return rv; + } + if (!NXTryLock(mutex->mutex)) return APR_EBUSY; return APR_SUCCESS; } +APR_DECLARE(apr_status_t) apr_thread_mutex_timedlock(apr_thread_mutex_t *mutex, + apr_time_t timeout, + int absolute) +{ + if (mutex->cond) { + apr_status_t rv; + NXLock(mutex->mutex); + if (mutex->locked) { + mutex->num_waiters++; + if (timeout < 0) { + rv = apr_thread_cond_dwait(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; + rv = APR_SUCCESS; + } + NXUnlock(mutex->mutex); + return rv; + } + + return APR_ENOTIMPL; +} + APR_DECLARE(apr_status_t) apr_thread_mutex_unlock(apr_thread_mutex_t *mutex) { + if (mutex->cond) { + apr_status_t rv; + NXLock(mutex->mutex); + if (!mutex->locked) { + rv = APR_EINVAL; + } + else if (mutex->num_waiters) { + rv = apr_thread_cond_signal(mutex->cond); + } + else { + mutex->locked = 0; + rv = APR_SUCCESS; + } + NXUnlock(mutex->mutex); + return rv; + } + NXUnlock(mutex->mutex); return APR_SUCCESS; } APR_DECLARE(apr_status_t) apr_thread_mutex_destroy(apr_thread_mutex_t *mutex) { - apr_status_t stat; - if ((stat = thread_mutex_cleanup(mutex)) == APR_SUCCESS) { - apr_pool_cleanup_kill(mutex->pool, mutex, thread_mutex_cleanup); - return APR_SUCCESS; + apr_status_t stat, rv = APR_SUCCESS; + if (mutex->cond) { + rv = apr_thread_cond_destroy(mutex->cond); + mutex->cond = NULL; + } + stat = apr_pool_cleanup_run(mutex->pool, mutex, thread_mutex_cleanup); + if (stat == APR_SUCCESS && rv) { + stat = rv; } return stat; } diff --git a/locks/os2/proc_mutex.c b/locks/os2/proc_mutex.c index 9b53c0bef..e873963f2 100644 --- a/locks/os2/proc_mutex.c +++ b/locks/os2/proc_mutex.c @@ -80,7 +80,7 @@ APR_DECLARE(apr_status_t) apr_proc_mutex_create(apr_proc_mutex_t **mutex, ULONG rc; char *semname; - if (mech != APR_LOCK_DEFAULT) { + if (mech != APR_LOCK_DEFAULT && mech != APR_LOCK_DEFAULT_TIMED) { return APR_ENOTIMPL; } @@ -156,6 +156,42 @@ APR_DECLARE(apr_status_t) apr_proc_mutex_trylock(apr_proc_mutex_t *mutex) +APR_DECLARE(apr_status_t) apr_proc_mutex_timedlock(apr_proc_mutex_t *mutex, + apr_time_t timeout, + int absolute) +{ + ULONG rc; + + if (timeout < 0) { + rc = DosRequestMutexSem(mutex->hMutex, SEM_INDEFINITE_WAIT); + } + else { + if (absolute) { + apr_time_t now = apr_time_now(); + if (timeout > now) { + timeout -= now; + } + else { + timeout = 0; + } + } + + rc = DosRequestMutexSem(mutex->hMutex, apr_time_as_msec(timeout)); + if (rc == ERROR_TIMEOUT) { + return APR_TIMEUP; + } + } + + if (rc == 0) { + mutex->owner = CurrentTid; + mutex->lock_count++; + } + + return APR_FROM_OS_ERROR(rc); +} + + + APR_DECLARE(apr_status_t) apr_proc_mutex_unlock(apr_proc_mutex_t *mutex) { ULONG rc; diff --git a/locks/os2/thread_cond.c b/locks/os2/thread_cond.c index ec6034f55..1b8698e7a 100644 --- a/locks/os2/thread_cond.c +++ b/locks/os2/thread_cond.c @@ -23,38 +23,172 @@ #include "apr_arch_file_io.h" #include <string.h> +#ifndef DCE_POSTONE +#define DCE_POSTONE 0x0800 // Post one flag +#endif + +static apr_status_t thread_cond_cleanup(void *data) +{ + apr_thread_cond_t *cv = data; + + if (cv->semaphore) { + DosCloseEventSem(cv->semaphore); + } + + if (cv->mutex) { + DosCloseMutexSem(cv->mutex); + } + + return APR_SUCCESS; +} + + + APR_DECLARE(apr_status_t) apr_thread_cond_create(apr_thread_cond_t **cond, apr_pool_t *pool) { - return APR_ENOTIMPL; + int rc; + apr_thread_cond_t *cv; + + cv = apr_pcalloc(pool, sizeof(**cond)); + rc = DosCreateEventSem(NULL, &cv->semaphore, DCE_POSTONE, FALSE); + + if (rc == 0) { + rc = DosCreateMutexSem(NULL, &cv->mutex, 0, FALSE); + } + + *cond = cv; + cv->pool = pool; + apr_pool_cleanup_register(cv->pool, cv, thread_cond_cleanup, + apr_pool_cleanup_null); + + return APR_FROM_OS_ERROR(rc); +} + + + +static apr_status_t thread_cond_timedwait(apr_thread_cond_t *cond, + apr_thread_mutex_t *mutex, + ULONG timeout_ms ) +{ + ULONG rc; + apr_status_t rv = APR_SUCCESS; + int wake = FALSE; + unsigned long generation; + + DosRequestMutexSem(cond->mutex, SEM_INDEFINITE_WAIT); + cond->num_waiting++; + generation = cond->generation; + DosReleaseMutexSem(cond->mutex); + + apr_thread_mutex_unlock(mutex); + + do { + rc = DosWaitEventSem(cond->semaphore, timeout_ms); + + DosRequestMutexSem(cond->mutex, SEM_INDEFINITE_WAIT); + + if (cond->num_wake) { + if (cond->generation != generation) { + cond->num_wake--; + cond->num_waiting--; + rv = APR_SUCCESS; + break; + } else { + wake = TRUE; + } + } + else if (rc != 0) { + cond->num_waiting--; + rv = APR_TIMEUP; + break; + } + + DosReleaseMutexSem(cond->mutex); + + if (wake) { + wake = FALSE; + DosPostEventSem(cond->semaphore); + } + } while (1); + + DosReleaseMutexSem(cond->mutex); + apr_thread_mutex_lock(mutex); + return rv; } + + APR_DECLARE(apr_status_t) apr_thread_cond_wait(apr_thread_cond_t *cond, apr_thread_mutex_t *mutex) { - return APR_ENOTIMPL; + return thread_cond_timedwait(cond, mutex, SEM_INDEFINITE_WAIT); } + + APR_DECLARE(apr_status_t) apr_thread_cond_timedwait(apr_thread_cond_t *cond, apr_thread_mutex_t *mutex, - apr_interval_time_t timeout){ - return APR_ENOTIMPL; + apr_interval_time_t timeout) +{ + ULONG timeout_ms = (timeout >= 0) ? apr_time_as_msec(timeout) + : SEM_INDEFINITE_WAIT; + return thread_cond_timedwait(cond, mutex, timeout_ms); } + + APR_DECLARE(apr_status_t) apr_thread_cond_signal(apr_thread_cond_t *cond) { - return APR_ENOTIMPL; + int wake = FALSE; + + DosRequestMutexSem(cond->mutex, SEM_INDEFINITE_WAIT); + + if (cond->num_waiting > cond->num_wake) { + wake = TRUE; + cond->num_wake++; + cond->generation++; + } + + DosReleaseMutexSem(cond->mutex); + + if (wake) { + DosPostEventSem(cond->semaphore); + } + + return APR_SUCCESS; } + + APR_DECLARE(apr_status_t) apr_thread_cond_broadcast(apr_thread_cond_t *cond) { - return APR_ENOTIMPL; + unsigned long num_wake = 0; + + DosRequestMutexSem(cond->mutex, SEM_INDEFINITE_WAIT); + + if (cond->num_waiting > cond->num_wake) { + num_wake = cond->num_waiting - cond->num_wake; + cond->num_wake = cond->num_waiting; + cond->generation++; + } + + DosReleaseMutexSem(cond->mutex); + + for (; num_wake; num_wake--) { + DosPostEventSem(cond->semaphore); + } + + return APR_SUCCESS; } + + APR_DECLARE(apr_status_t) apr_thread_cond_destroy(apr_thread_cond_t *cond) { - return APR_ENOTIMPL; + return apr_pool_cleanup_run(cond->pool, cond, thread_cond_cleanup); } -APR_POOL_IMPLEMENT_ACCESSOR(thread_cond) + +APR_POOL_IMPLEMENT_ACCESSOR(thread_cond) diff --git a/locks/os2/thread_mutex.c b/locks/os2/thread_mutex.c index 5d8436be4..26245839d 100644 --- a/locks/os2/thread_mutex.c +++ b/locks/os2/thread_mutex.c @@ -71,6 +71,36 @@ APR_DECLARE(apr_status_t) apr_thread_mutex_trylock(apr_thread_mutex_t *mutex) +APR_DECLARE(apr_status_t) apr_thread_mutex_timedlock(apr_thread_mutex_t *mutex, + apr_time_t timeout, + int absolute) +{ + ULONG rc; + + if (timeout < 0) { + rc = DosRequestMutexSem(mutex->hMutex, SEM_INDEFINITE_WAIT); + } + else { + if (absolute) { + apr_time_t now = apr_time_now(); + if (timeout > now) { + timeout -= now; + } + else { + timeout = 0; + } + } + rc = DosRequestMutexSem(mutex->hMutex, apr_time_as_msec(usec)); + if (rc == ERROR_TIMEOUT) { + return APR_TIMEUP; + } + } + + return APR_FROM_OS_ERROR(rc); +} + + + APR_DECLARE(apr_status_t) apr_thread_mutex_unlock(apr_thread_mutex_t *mutex) { ULONG rc = DosReleaseMutexSem(mutex->hMutex); diff --git a/locks/unix/global_mutex.c b/locks/unix/global_mutex.c index ca3b86e46..19485c487 100644 --- a/locks/unix/global_mutex.c +++ b/locks/unix/global_mutex.c @@ -141,6 +141,40 @@ APR_DECLARE(apr_status_t) apr_global_mutex_trylock(apr_global_mutex_t *mutex) return rv; } +APR_DECLARE(apr_status_t) apr_global_mutex_timedlock(apr_global_mutex_t *mutex, + apr_time_t timeout, + int absolute) +{ + apr_status_t rv; + +#if APR_HAS_THREADS + if (mutex->thread_mutex) { + if (timeout >= 0 && !absolute) { + timeout += apr_time_now(); + absolute = 1; + } + rv = apr_thread_mutex_timedlock(mutex->thread_mutex, timeout, + absolute); + if (rv != APR_SUCCESS) { + return rv; + } + } +#endif /* APR_HAS_THREADS */ + + rv = apr_proc_mutex_timedlock(mutex->proc_mutex, timeout, + absolute); + +#if APR_HAS_THREADS + if (rv != APR_SUCCESS) { + if (mutex->thread_mutex) { + (void)apr_thread_mutex_unlock(mutex->thread_mutex); + } + } +#endif /* APR_HAS_THREADS */ + + return rv; +} + APR_DECLARE(apr_status_t) apr_global_mutex_unlock(apr_global_mutex_t *mutex) { apr_status_t rv; diff --git a/locks/unix/proc_mutex.c b/locks/unix/proc_mutex.c index 7eff5e3f3..0a4cf180d 100644 --- a/locks/unix/proc_mutex.c +++ b/locks/unix/proc_mutex.c @@ -184,6 +184,41 @@ static apr_status_t proc_mutex_posix_tryacquire(apr_proc_mutex_t *mutex) return APR_SUCCESS; } +static apr_status_t proc_mutex_posix_timedacquire(apr_proc_mutex_t *mutex, + apr_time_t timeout, + int absolute) +{ +#if HAVE_SEM_TIMEDWAIT + if (timeout < 0) { + return proc_mutex_posix_acquire(mutex); + } + else { + int rc; + 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 */ + + do { + rc = sem_timedwait(mutex->psem_interproc, &abstime); + } while (rc < 0 && errno == EINTR); + if (rc < 0) { + if (errno == ETIMEDOUT) { + return APR_TIMEUP; + } + return errno; + } + } + mutex->curr_locked = 1; + return APR_SUCCESS; +#else + return APR_ENOTIMPL; +#endif +} + static apr_status_t proc_mutex_posix_release(apr_proc_mutex_t *mutex) { mutex->curr_locked = 0; @@ -205,6 +240,7 @@ static const apr_proc_mutex_unix_lock_methods_t mutex_posixsem_methods = proc_mutex_posix_create, proc_mutex_posix_acquire, proc_mutex_posix_tryacquire, + proc_mutex_posix_timedacquire, proc_mutex_posix_release, proc_mutex_posix_cleanup, proc_mutex_no_child_init, @@ -303,6 +339,40 @@ static apr_status_t proc_mutex_sysv_tryacquire(apr_proc_mutex_t *mutex) return APR_SUCCESS; } +static apr_status_t proc_mutex_sysv_timedacquire(apr_proc_mutex_t *mutex, + apr_time_t timeout, + int absolute) +{ +#if HAVE_SEMTIMEDOP + if (timeout < 0) { + return proc_mutex_sysv_acquire(mutex); + } + else { + int rc; + 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 */ + do { + rc = semtimedop(mutex->interproc->filedes, &proc_mutex_op_on, 1, + &abstime); + } while (rc < 0 && errno == EINTR); + if (rc < 0) { + if (errno == EAGAIN) { + return APR_TIMEUP; + } + return errno; + } + } + mutex->curr_locked = 1; + return APR_SUCCESS; +#else + return APR_ENOTIMPL; +#endif +} + static apr_status_t proc_mutex_sysv_release(apr_proc_mutex_t *mutex) { int rc; @@ -345,6 +415,7 @@ static const apr_proc_mutex_unix_lock_methods_t mutex_sysv_methods = proc_mutex_sysv_create, proc_mutex_sysv_acquire, proc_mutex_sysv_tryacquire, + proc_mutex_sysv_timedacquire, proc_mutex_sysv_release, proc_mutex_sysv_cleanup, proc_mutex_no_child_init, @@ -518,7 +589,50 @@ static apr_status_t proc_mutex_proc_pthread_tryacquire(apr_proc_mutex_t *mutex) #endif } mutex->curr_locked = 1; - return rv; + return APR_SUCCESS; +} + +static apr_status_t +proc_mutex_proc_pthread_timedacquire(apr_proc_mutex_t *mutex, + apr_time_t timeout, + int absolute) +{ + if (timeout < 0) { + return proc_mutex_proc_pthread_acquire(mutex); + } + else { + apr_status_t rv; + 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 */ + + if ((rv = pthread_mutex_timedlock(mutex->pthread_interproc, + &abstime))) { +#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) { + pthread_mutex_consistent_np(mutex->pthread_interproc); + rv = APR_SUCCESS; + } + else + return rv; +#else + return rv; +#endif + } + } + mutex->curr_locked = 1; + return APR_SUCCESS; } static apr_status_t proc_mutex_proc_pthread_release(apr_proc_mutex_t *mutex) @@ -541,6 +655,7 @@ static const apr_proc_mutex_unix_lock_methods_t mutex_proc_pthread_methods = proc_mutex_proc_pthread_create, proc_mutex_proc_pthread_acquire, proc_mutex_proc_pthread_tryacquire, + proc_mutex_proc_pthread_timedacquire, proc_mutex_proc_pthread_release, proc_mutex_proc_pthread_cleanup, proc_mutex_no_child_init, @@ -652,6 +767,13 @@ 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; @@ -692,6 +814,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_fcntl_release, proc_mutex_fcntl_cleanup, proc_mutex_no_child_init, @@ -783,6 +906,13 @@ 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; @@ -847,6 +977,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_flock_release, proc_mutex_flock_cleanup, proc_mutex_flock_child_init, @@ -920,6 +1051,21 @@ static apr_status_t proc_mutex_choose_method(apr_proc_mutex_t *new_mutex, apr_lo return APR_ENOTIMPL; #endif break; + case APR_LOCK_DEFAULT_TIMED: +#if APR_HAS_PROC_PTHREAD_SERIALIZE \ + && defined(HAVE_PTHREAD_MUTEX_ROBUST) \ + && defined(HAVE_PTHREAD_MUTEX_TIMEDLOCK) + new_mutex->inter_meth = &mutex_proc_pthread_methods; +#elif APR_HAS_SYSVSEM_SERIALIZE \ + && defined(HAVE_SEMTIMEDOP) + new_mutex->inter_meth = &mutex_sysv_methods; +#elif APR_HAS_POSIXSEM_SERIALIZE \ + && defined(HAVE_SEM_TIMEDWAIT) + new_mutex->inter_meth = &mutex_posixsem_methods; +#else + return APR_ENOTIMPL; +#endif + break; default: return APR_ENOTIMPL; } @@ -991,6 +1137,13 @@ APR_DECLARE(apr_status_t) apr_proc_mutex_trylock(apr_proc_mutex_t *mutex) return mutex->meth->tryacquire(mutex); } +APR_DECLARE(apr_status_t) apr_proc_mutex_timedlock(apr_proc_mutex_t *mutex, + apr_time_t timeout, + int absolute) +{ + return mutex->meth->timedacquire(mutex, timeout, absolute); +} + APR_DECLARE(apr_status_t) apr_proc_mutex_unlock(apr_proc_mutex_t *mutex) { return mutex->meth->release(mutex); diff --git a/locks/unix/thread_cond.c b/locks/unix/thread_cond.c index db7dd4f0d..3c8e3170a 100644 --- a/locks/unix/thread_cond.c +++ b/locks/unix/thread_cond.c @@ -79,21 +79,31 @@ APR_DECLARE(apr_status_t) apr_thread_cond_timedwait(apr_thread_cond_t *cond, apr_interval_time_t timeout) { apr_status_t rv; - apr_time_t then; - struct timespec abstime; + if (timeout < 0) { + rv = pthread_cond_wait(&cond->cond, &mutex->mutex); +#ifdef HAVE_ZOS_PTHREADS + if (rv) { + rv = errno; + } +#endif + } + else { + apr_time_t then; + struct timespec abstime; - then = apr_time_now() + timeout; - abstime.tv_sec = apr_time_sec(then); - abstime.tv_nsec = apr_time_usec(then) * 1000; /* nanoseconds */ + then = apr_time_now() + timeout; + abstime.tv_sec = apr_time_sec(then); + abstime.tv_nsec = apr_time_usec(then) * 1000; /* nanoseconds */ - rv = pthread_cond_timedwait(&cond->cond, &mutex->mutex, &abstime); + rv = pthread_cond_timedwait(&cond->cond, &mutex->mutex, &abstime); #ifdef HAVE_ZOS_PTHREADS - if (rv) { - rv = errno; - } + if (rv) { + rv = errno; + } #endif - if (ETIMEDOUT == rv) { - return APR_TIMEUP; + if (ETIMEDOUT == rv) { + return APR_TIMEUP; + } } return rv; } diff --git a/locks/unix/thread_mutex.c b/locks/unix/thread_mutex.c index 73fd1e146..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); @@ -89,13 +102,45 @@ APR_DECLARE(apr_status_t) apr_thread_mutex_lock(apr_thread_mutex_t *mutex) { apr_status_t rv; + 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++; + rv = apr_thread_cond_wait(mutex->cond, mutex); + 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 + } + + return rv; + } + rv = pthread_mutex_lock(&mutex->mutex); #ifdef HAVE_ZOS_PTHREADS if (rv) { rv = errno; } #endif - + return rv; } @@ -103,6 +148,36 @@ APR_DECLARE(apr_status_t) apr_thread_mutex_trylock(apr_thread_mutex_t *mutex) { apr_status_t rv; + 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) { + rv = APR_EBUSY; + } + else { + mutex->locked = 1; + } + + rv2 = pthread_mutex_unlock(&mutex->mutex); + if (rv2) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#else + rv = rv2; +#endif + } + + return rv; + } + rv = pthread_mutex_trylock(&mutex->mutex); if (rv) { #ifdef HAVE_ZOS_PTHREADS @@ -114,10 +189,130 @@ APR_DECLARE(apr_status_t) apr_thread_mutex_trylock(apr_thread_mutex_t *mutex) return APR_SUCCESS; } +APR_DECLARE(apr_status_t) apr_thread_mutex_timedlock(apr_thread_mutex_t *mutex, + apr_time_t timeout, + int absolute) +{ + apr_status_t rv = APR_ENOTIMPL; + +#ifdef HAVE_PTHREAD_MUTEX_TIMEDLOCK + if (timeout < 0) { + rv = pthread_mutex_lock(&mutex->mutex); + if (rv) { +#ifdef HAVE_ZOS_PTHREADS + 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_mutex_timedlock(&mutex->mutex, &abstime); + if (rv) { +#ifdef HAVE_ZOS_PTHREADS + rv = errno; +#endif + if (rv == ETIMEDOUT) { + rv = APR_TIMEUP; + } + } + } + +#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; +} + APR_DECLARE(apr_status_t) apr_thread_mutex_unlock(apr_thread_mutex_t *mutex) { apr_status_t status; + if (mutex->cond) { + apr_status_t stat2; + + status = pthread_mutex_lock(&mutex->mutex); + if (status) { +#ifdef HAVE_ZOS_PTHREADS + status = errno; +#endif + return status; + } + + if (!mutex->locked) { + status = APR_EINVAL; + } + else if (mutex->num_waiters) { + status = apr_thread_cond_signal(mutex->cond); + } + else { + mutex->locked = 0; + status = APR_SUCCESS; + } + + stat2 = pthread_mutex_unlock(&mutex->mutex); + if (stat2) { +#ifdef HAVE_ZOS_PTHREADS + status = errno; +#else + status = stat2; +#endif + } + + return status; + } + status = pthread_mutex_unlock(&mutex->mutex); #ifdef HAVE_ZOS_PTHREADS if (status) { @@ -130,7 +325,17 @@ APR_DECLARE(apr_status_t) apr_thread_mutex_unlock(apr_thread_mutex_t *mutex) APR_DECLARE(apr_status_t) apr_thread_mutex_destroy(apr_thread_mutex_t *mutex) { - return apr_pool_cleanup_run(mutex->pool, mutex, thread_mutex_cleanup); + apr_status_t rv, rv2 = APR_SUCCESS; + + if (mutex->cond) { + rv2 = apr_thread_cond_destroy(mutex->cond); + } + rv = apr_pool_cleanup_run(mutex->pool, mutex, thread_mutex_cleanup); + if (rv == APR_SUCCESS) { + rv = rv2; + } + + return rv; } APR_POOL_IMPLEMENT_ACCESSOR(thread_mutex) diff --git a/locks/win32/proc_mutex.c b/locks/win32/proc_mutex.c index 38366f185..5ec9b2648 100644 --- a/locks/win32/proc_mutex.c +++ b/locks/win32/proc_mutex.c @@ -160,6 +160,37 @@ APR_DECLARE(apr_status_t) apr_proc_mutex_trylock(apr_proc_mutex_t *mutex) return apr_get_os_error(); } +APR_DECLARE(apr_status_t) apr_proc_mutex_timedlock(apr_proc_mutex_t *mutex, + apr_time_t timeout, + int absolute) +{ + DWORD rv; + + if (timeout < 0) { + rv = WaitForSingleObject(mutex->handle, INFINITE); + } + else { + if (absolute) { + apr_time_t now = apr_time_now(); + if (timeout > now) { + timeout -= now; + } + else { + timeout = 0; + } + } + rv = WaitForSingleObject(mutex->handle, apr_time_as_msec(timeout)); + if (rv == WAIT_TIMEOUT) { + return APR_TIMEUP; + } + } + + if (rv == WAIT_OBJECT_0 || rv == WAIT_ABANDONED) { + return APR_SUCCESS; + } + return apr_get_os_error(); +} + APR_DECLARE(apr_status_t) apr_proc_mutex_unlock(apr_proc_mutex_t *mutex) { if (ReleaseMutex(mutex->handle) == 0) { diff --git a/locks/win32/thread_cond.c b/locks/win32/thread_cond.c index 60286e542..b2ac1c8ff 100644 --- a/locks/win32/thread_cond.c +++ b/locks/win32/thread_cond.c @@ -61,9 +61,9 @@ APR_DECLARE(apr_status_t) apr_thread_cond_destroy(apr_thread_cond_t *cond) return apr_pool_cleanup_run(cond->pool, cond, thread_cond_cleanup); } -static APR_INLINE apr_status_t _thread_cond_timedwait(apr_thread_cond_t *cond, - apr_thread_mutex_t *mutex, - DWORD timeout_ms ) +static APR_INLINE apr_status_t thread_cond_timedwait(apr_thread_cond_t *cond, + apr_thread_mutex_t *mutex, + DWORD timeout_ms ) { DWORD res; apr_status_t rv; @@ -115,16 +115,15 @@ static APR_INLINE apr_status_t _thread_cond_timedwait(apr_thread_cond_t *cond, APR_DECLARE(apr_status_t) apr_thread_cond_wait(apr_thread_cond_t *cond, apr_thread_mutex_t *mutex) { - return _thread_cond_timedwait(cond, mutex, INFINITE); + return thread_cond_timedwait(cond, mutex, INFINITE); } APR_DECLARE(apr_status_t) apr_thread_cond_timedwait(apr_thread_cond_t *cond, apr_thread_mutex_t *mutex, apr_interval_time_t timeout) { - DWORD timeout_ms = (DWORD) apr_time_as_msec(timeout); - - return _thread_cond_timedwait(cond, mutex, timeout_ms); + DWORD timeout_ms = (timeout >= 0) ? apr_time_as_msec(timeout) : INFINITE; + return thread_cond_timedwait(cond, mutex, timeout_ms); } APR_DECLARE(apr_status_t) apr_thread_cond_signal(apr_thread_cond_t *cond) diff --git a/locks/win32/thread_mutex.c b/locks/win32/thread_mutex.c index 9b10d7278..cd0ccf5ba 100644 --- a/locks/win32/thread_mutex.c +++ b/locks/win32/thread_mutex.c @@ -54,6 +54,10 @@ APR_DECLARE(apr_status_t) apr_thread_mutex_create(apr_thread_mutex_t **mutex, (*mutex)->type = thread_mutex_unnested_event; (*mutex)->handle = CreateEvent(NULL, FALSE, TRUE, NULL); } + else if (flags & APR_THREAD_MUTEX_TIMED) { + (*mutex)->type = thread_mutex_nested_mutex; + (*mutex)->handle = CreateMutex(NULL, FALSE, NULL); + } else { #if APR_HAS_UNICODE_FS /* Critical Sections are terrific, performance-wise, on NT. @@ -63,6 +67,7 @@ APR_DECLARE(apr_status_t) apr_thread_mutex_create(apr_thread_mutex_t **mutex, IF_WIN_OS_IS_UNICODE { InitializeCriticalSection(&(*mutex)->section); (*mutex)->type = thread_mutex_critical_section; + (*mutex)->handle = NULL; } #endif #if APR_HAS_ANSI_FS @@ -86,9 +91,9 @@ APR_DECLARE(apr_status_t) apr_thread_mutex_lock(apr_thread_mutex_t *mutex) } else { DWORD rv = WaitForSingleObject(mutex->handle, INFINITE); - if ((rv != WAIT_OBJECT_0) && (rv != WAIT_ABANDONED)) { + if ((rv != WAIT_OBJECT_0) && (rv != WAIT_ABANDONED)) { return (rv == WAIT_TIMEOUT) ? APR_EBUSY : apr_get_os_error(); - } + } } return APR_SUCCESS; } @@ -102,13 +107,44 @@ APR_DECLARE(apr_status_t) apr_thread_mutex_trylock(apr_thread_mutex_t *mutex) } else { DWORD rv = WaitForSingleObject(mutex->handle, 0); - if ((rv != WAIT_OBJECT_0) && (rv != WAIT_ABANDONED)) { + if ((rv != WAIT_OBJECT_0) && (rv != WAIT_ABANDONED)) { return (rv == WAIT_TIMEOUT) ? APR_EBUSY : apr_get_os_error(); - } + } } return APR_SUCCESS; } +APR_DECLARE(apr_status_t) apr_thread_mutex_timedlock(apr_thread_mutex_t *mutex, + apr_time_t timeout, + int absolute) +{ + if (mutex->type != thread_mutex_critical_section) { + DWORD rv, timeout_ms; + if (timeout < 0) { + timeout_ms = INFINITE; + } + else { + if (absolute) { + apr_time_t now = apr_time_now(); + if (timeout > now) { + timeout -= now; + } + else { + timeout = 0; + } + } + timeout_ms = apr_time_as_msec(timeout); + } + rv = WaitForSingleObject(mutex->handle, timeout_ms); + if ((rv != WAIT_OBJECT_0) && (rv != WAIT_ABANDONED)) { + return (rv == WAIT_TIMEOUT) ? APR_TIMEUP : apr_get_os_error(); + } + return APR_SUCCESS; + } + + return APR_ENOTIMPL; +} + APR_DECLARE(apr_status_t) apr_thread_mutex_unlock(apr_thread_mutex_t *mutex) { if (mutex->type == thread_mutex_critical_section) { |