Skip to content

Commit

Permalink
Split APR_THREAD_MUTEX_DEFAULT with a new APR_THREAD_MUTEX_UNNESTED
Browse files Browse the repository at this point in the history
  which guarentees unnested lock behavior, keep APR_THREAD_MUTEX_DEFAULT
  on Win32, Netware and OS2 as nested locks, leave Unix and BeOS with
  unnested locks by default.

  Needs an implementation on Netware and OS2 for UNNESTED locks, for now
  return APR_ENOTIMPL.

  Required for absolute locks in series for Win32 on the same thread,
  since CriticalSection objects are blindingly fast without contention,
  but they will always nest on the same thread.


git-svn-id: https://svn.apache.org/repos/asf/apr/apr/trunk@63440 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information
wrowe committed May 29, 2002
1 parent 86f9f2d commit b370900
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 16 deletions.
7 changes: 6 additions & 1 deletion include/apr_thread_mutex.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ typedef struct apr_thread_mutex_t apr_thread_mutex_t;

#define APR_THREAD_MUTEX_DEFAULT 0x0
#define APR_THREAD_MUTEX_NESTED 0x1
#define APR_THREAD_MUTEX_UNNESTED 0x2

/* Delayed the include to avoid a circular reference */
#include "apr_pools.h"
Expand All @@ -89,10 +90,14 @@ typedef struct apr_thread_mutex_t apr_thread_mutex_t;
* stored.
* @param flags Or'ed value of:
* <PRE>
* APR_THREAD_MUTEX_DEFAULT normal lock behavior (non-recursive).
* APR_THREAD_MUTEX_DEFAULT platform-optimal lock behavior.
* APR_THREAD_MUTEX_NESTED enable nested (recursive) locks.
* APR_THREAD_MUTEX_UNNESTED disable nested locks (non-recursive).
* </PRE>
* @param pool the pool from which to allocate the mutex.
* @tip Be cautious in using APR_THREAD_MUTEX_DEFAULT. While this is the
* most optimial mutex based on a given platform's performance charateristics,
* it will behave as either a nested or an unnested lock.
*/
APR_DECLARE(apr_status_t) apr_thread_mutex_create(apr_thread_mutex_t **mutex,
unsigned int flags,
Expand Down
16 changes: 14 additions & 2 deletions include/arch/win32/thread_mutex.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,21 @@

#include "apr_pools.h"

typedef enum thread_mutex_type {
thread_mutex_critical_section,
thread_mutex_unnested_event,
thread_mutex_nested_mutex
} thread_mutex_type;

/* handle applies only to unnested_event on all platforms
* and nested_mutex on Win9x only. Otherwise critical_section
* is used for NT nexted mutexes providing optimal performance.
*/
struct apr_thread_mutex_t {
apr_pool_t *pool;
CRITICAL_SECTION section;
apr_pool_t *pool;
thread_mutex_type type;
HANDLE handle;
CRITICAL_SECTION section;
};

#endif /* THREAD_MUTEX_H */
Expand Down
4 changes: 4 additions & 0 deletions locks/beos/thread_mutex.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,10 @@ APR_DECLARE(apr_status_t) apr_thread_mutex_create(apr_thread_mutex_t **mutex,
new_m->LockCount = 0;
new_m->Lock = stat;
new_m->pool = pool;

/* Optimal default is APR_THREAD_MUTEX_UNNESTED,
* no additional checks required for either flag.
*/
new_m->nested = flags & APR_THREAD_MUTEX_NESTED;

apr_pool_cleanup_register(new_m->pool, (void *)new_m, _thread_mutex_cleanup,
Expand Down
6 changes: 5 additions & 1 deletion locks/netware/thread_mutex.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,18 @@ APR_DECLARE(apr_status_t) apr_thread_mutex_create(apr_thread_mutex_t **mutex,
{
apr_thread_mutex_t *new_mutex = NULL;

/* XXX: Implement _UNNESTED flavor and favor _DEFAULT for performance
*/
if (flags & APR_THREAD_MUTEX_UNNESTED) {
return APR_ENOTIMPL;
}
new_mutex = (apr_thread_mutex_t *)apr_pcalloc(pool, sizeof(apr_thread_mutex_t));

if(new_mutex ==NULL) {
return APR_ENOMEM;
}
new_mutex->pool = pool;

/* FIXME: only use recursive locks if (flags & APR_THREAD_MUTEX_NESTED) */
new_mutex->mutex = NXMutexAlloc(NX_MUTEX_RECURSIVE, NULL, NULL);

if(new_mutex->mutex == NULL)
Expand Down
3 changes: 3 additions & 0 deletions locks/os2/thread_mutex.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ static apr_status_t thread_mutex_cleanup(void *themutex)



/* XXX: Need to respect APR_THREAD_MUTEX_[UN]NESTED flags argument
* or return APR_ENOTIMPL!!!
*/
APR_DECLARE(apr_status_t) apr_thread_mutex_create(apr_thread_mutex_t **mutex,
unsigned int flags,
apr_pool_t *pool)
Expand Down
4 changes: 4 additions & 0 deletions locks/unix/thread_mutex.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,10 @@ APR_DECLARE(apr_status_t) apr_thread_mutex_create(apr_thread_mutex_t **mutex,
}

new_mutex->pool = pool;

/* Optimal default is APR_THREAD_MUTEX_UNNESTED,
* no additional checks required for either flag.
*/
new_mutex->nested = flags & APR_THREAD_MUTEX_NESTED;

if ((rv = pthread_mutexattr_init(&mattr))) {
Expand Down
81 changes: 69 additions & 12 deletions locks/win32/thread_mutex.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,14 @@ static apr_status_t thread_mutex_cleanup(void *data)
{
apr_thread_mutex_t *lock = data;

DeleteCriticalSection(&lock->section);
if (lock->type == thread_mutex_critical_section) {
DeleteCriticalSection(&lock->section);
}
else {
if (!CloseHandle(lock->handle)) {
return apr_get_os_error();
}
}
return APR_SUCCESS;
}

Expand All @@ -76,34 +83,84 @@ APR_DECLARE(apr_status_t) apr_thread_mutex_create(apr_thread_mutex_t **mutex,
(*mutex) = (apr_thread_mutex_t *)apr_palloc(pool, sizeof(**mutex));

(*mutex)->pool = pool;
/* FIXME: Implement nested (aka recursive) locks or use a native
* win32 implementation if available. */
InitializeCriticalSection(&(*mutex)->section);

if (flags & APR_THREAD_MUTEX_UNNESTED) {
/* Use an auto-reset signaled event, ready to accept one
* waiting thread.
*/
(*mutex)->type = thread_mutex_unnested_event;
(*mutex)->handle = CreateEvent(NULL, FALSE, TRUE, NULL);
}
else {
#if APR_HAS_UNICODE_FS
/* Critical Sections are terrific, performance-wise, on NT.
* On Win9x, we cannot 'try' on a critical section, so we
* use a [slower] mutex object, instead.
*/
IF_WIN_OS_IS_UNICODE {
(*mutex)->type = thread_mutex_critical_section;
InitializeCriticalSection(&(*mutex)->section);
}
#endif
#if APR_HAS_ANSI_FS
ELSE_WIN_OS_IS_ANSI {
(*mutex)->type = thread_mutex_nested_mutex;
(*mutex)->handle = CreateMutex(NULL, FALSE, NULL);

}
#endif
}

apr_pool_cleanup_register((*mutex)->pool, (*mutex), thread_mutex_cleanup,
apr_pool_cleanup_null);
return APR_SUCCESS;
}

APR_DECLARE(apr_status_t) apr_thread_mutex_lock(apr_thread_mutex_t *mutex)
{
EnterCriticalSection(&mutex->section);
if (mutex->type == thread_mutex_critical_section) {
EnterCriticalSection(&mutex->section);
}
else {
DWORD rv = WaitForSingleObject(mutex->handle, INFINITE);
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_trylock(apr_thread_mutex_t *mutex)
{
if (apr_os_level < APR_WIN_NT) {
return APR_ENOTIMPL;
}
if (TryEnterCriticalSection(&mutex->section)) {
return APR_SUCCESS;
if (mutex->type == thread_mutex_critical_section) {
if (!TryEnterCriticalSection(&mutex->section)) {
return APR_EBUSY;
}
}
return APR_EBUSY;
else {
DWORD rv = WaitForSingleObject(mutex->handle, 0);
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_unlock(apr_thread_mutex_t *mutex)
{
LeaveCriticalSection(&mutex->section);
if (mutex->type == thread_mutex_critical_section) {
LeaveCriticalSection(&mutex->section);
}
else if (mutex->type == thread_mutex_unnested_event) {
if (!SetEvent(mutex->handle)) {
return apr_get_os_error();
}
}
else if (mutex->type == thread_mutex_nested_mutex) {
if (!ReleaseMutex(mutex->handle)) {
return apr_get_os_error();
}
}
return APR_SUCCESS;
}

Expand Down

0 comments on commit b370900

Please sign in to comment.