diff options
Diffstat (limited to 'src/dbinc/mutex.h')
-rw-r--r-- | src/dbinc/mutex.h | 110 |
1 files changed, 75 insertions, 35 deletions
diff --git a/src/dbinc/mutex.h b/src/dbinc/mutex.h index b699142c..334d8f96 100644 --- a/src/dbinc/mutex.h +++ b/src/dbinc/mutex.h @@ -1,7 +1,7 @@ /* * See the file LICENSE for redistribution information. * - * Copyright (c) 1996, 2012 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2015 Oracle and/or its affiliates. All rights reserved. * * $Id$ */ @@ -24,10 +24,14 @@ extern "C" { #endif /* - * By default, spin 50 times per processor if fail to acquire a test-and-set - * mutex, we have anecdotal evidence it's a reasonable value. + * These specify the default spin parameters for test-and-set mutexes. A single + * processor system spins just once, a multiprocessor system spins 50 times per + * processor up to a default maximum of 200. This limit reduces excessive + * busy-waiting on machines with many hyperthreads. We have anecdotal evidence + * that these are reasonable default values. */ #define MUTEX_SPINS_PER_PROCESSOR 50 +#define MUTEX_SPINS_DEFAULT_MAX 200 /* * Mutexes are represented by unsigned, 32-bit integral values. As the @@ -163,13 +167,6 @@ static inline int __db_pthread_mutex_tryreadlock(ENV *env, db_mutex_t mutex) #define __mutex_rdlock(a, b) __db_win32_mutex_readlock(a, b) #define __mutex_tryrdlock(a, b) __db_win32_mutex_tryreadlock(a, b) #endif -#elif defined(HAVE_MUTEX_FCNTL) -#define __mutex_init(a, b, c) __db_fcntl_mutex_init(a, b, c) -#define __mutex_lock(a, b) __db_fcntl_mutex_lock(a, b, 0) -#define __mutex_timedlock(a, b, c) __db_fcntl_lock(a, b, c) -#define __mutex_trylock(a, b) __db_fcntl_mutex_trylock(a, b) -#define __mutex_unlock(a, b) __db_fcntl_mutex_unlock(a, b) -#define __mutex_destroy(a, b) __db_fcntl_mutex_destroy(a, b) #else #define __mutex_init(a, b, c) __db_tas_mutex_init(a, b, c) #define __mutex_lock(a, b) __db_tas_mutex_lock(a, b, 0) @@ -184,9 +181,8 @@ static inline int __db_pthread_mutex_tryreadlock(ENV *env, db_mutex_t mutex) #endif /* - * When there is no method to get a shared latch, fall back to - * implementing __mutex_rdlock() as getting an exclusive one. - * This occurs either when !HAVE_SHARED_LATCHES or HAVE_MUTEX_FCNTL. + * When there is no method to get a shared latch, fall back to implementing + * __mutex_rdlock() as an exclusive one. This may no longer be supported? */ #ifndef __mutex_rdlock #define __mutex_rdlock(a, b) __mutex_lock(a, b) @@ -199,17 +195,25 @@ static inline int __db_pthread_mutex_tryreadlock(ENV *env, db_mutex_t mutex) * Lock/unlock a mutex. If the mutex was never required, the thread of * control can proceed without it. * - * We never fail to acquire or release a mutex without panicing. Simplify + * We rarely fail to acquire or release a mutex without panicing. Simplify * the macros to always return a panic value rather than saving the actual - * return value of the mutex routine. + * return value of the mutex routine. Use MUTEX_LOCK_RET() when the caller has + * a code path for a mutex failure, e.g., when cleaning up after a panic. */ #ifdef HAVE_MUTEX_SUPPORT #define MUTEX_LOCK(env, mutex) do { \ - if ((mutex) != MUTEX_INVALID && \ - __mutex_lock(env, mutex) != 0) \ + if ((mutex) != MUTEX_INVALID && __mutex_lock(env, mutex) != 0) \ return (DB_RUNRECOVERY); \ } while (0) +#define MUTEX_LOCK_RET(env, mutex) \ + ((mutex) == MUTEX_INVALID ? 0 : __mutex_lock(env, mutex)) + +/* + * Always check the return value of MUTEX_TRYLOCK()! Expect 0 on success, + * or possibly DB_RUNRECOVERY for failchk. + */ + /* * Always check the return value of MUTEX_TRYLOCK()! Expect 0 on success, * or DB_LOCK_NOTGRANTED, or possibly DB_RUNRECOVERY for failchk. @@ -217,9 +221,7 @@ static inline int __db_pthread_mutex_tryreadlock(ENV *env, db_mutex_t mutex) #define MUTEX_TRYLOCK(env, mutex) \ (((mutex) == MUTEX_INVALID) ? 0 : __mutex_trylock(env, mutex)) -/* - * Acquire a DB_MUTEX_SHARED "mutex" in shared mode. - */ +/* Acquire a latch (a DB_MUTEX_SHARED "mutex") in shared mode. */ #define MUTEX_READLOCK(env, mutex) do { \ if ((mutex) != MUTEX_INVALID && \ __mutex_rdlock(env, mutex) != 0) \ @@ -234,30 +236,68 @@ static inline int __db_pthread_mutex_tryreadlock(ENV *env, db_mutex_t mutex) return (DB_RUNRECOVERY); \ } while (0) -#define MUTEX_WAIT(env, mutex, duration) do { \ - int __ret; \ - if ((mutex) != MUTEX_INVALID && \ - (__ret = __mutex_timedlock(env, mutex, duration)) != 0 && \ - __ret != DB_TIMEOUT) \ - return (DB_RUNRECOVERY); \ +#define MUTEX_WAIT(env, mutex, duration) do { \ + int __ret; \ + if ((mutex) != MUTEX_INVALID && \ + (__ret = __mutex_timedlock(env, mutex, duration)) != 0 && \ + __ret != DB_TIMEOUT) \ + return (DB_RUNRECOVERY); \ } while (0) + +/* + * Check that a particular mutex is exclusively held at least by someone, not + * necessarily the current thread. + */ +#define MUTEX_IS_OWNED(env, mutex) \ + (mutex == MUTEX_INVALID || !MUTEX_ON(env) || \ + F_ISSET(env->dbenv, DB_ENV_NOLOCKING) || \ + F_ISSET(MUTEXP_SET(env, mutex), DB_MUTEX_LOCKED)) #else /* * There are calls to lock/unlock mutexes outside of #ifdef's -- replace * the call with something the compiler can discard, but which will make - * if-then-else blocks work correctly. + * if-then-else blocks work correctly, and suppress unused variable messages. + */ +#define MUTEX_LOCK(env, mutex) { env = (env); mutex = (mutex); } +#define MUTEX_LOCK_RET(env, mutex) ( env = (env), mutex = (mutex), 0) +#define MUTEX_TRYLOCK(env, mutex) ( env = (env), mutex = (mutex), 0) +#define MUTEX_READLOCK(env, mutex) { env = (env); mutex = (mutex); } +#define MUTEX_TRY_READLOCK(env, mutex) ( env = (env), mutex = (mutex), 0 ) +#define MUTEX_UNLOCK(env, mutex) { env = (env); mutex = (mutex); } +#define MUTEX_REQUIRED(env, mutex) { env = (env); mutex = (mutex); } +#define MUTEX_REQUIRED_READ(env, mutex) { env = (env); mutex = (mutex); } +#define MUTEX_WAIT(env, mutex, duration) { \ + (env) = (env); (mutex) = (mutex); (duration) = (duration); \ +} + +/* + * Every MUTEX_IS_OWNED() caller expects to own it. When there is no mutex + * support, act as if we have ownership. */ -#define MUTEX_LOCK(env, mutex) (mutex) = (mutex) -#define MUTEX_TRYLOCK(env, mutex) (mutex) = (mutex) -#define MUTEX_READLOCK(env, mutex) (mutex) = (mutex) -#define MUTEX_TRY_READLOCK(env, mutex) (mutex) = (mutex) -#define MUTEX_UNLOCK(env, mutex) (mutex) = (mutex) -#define MUTEX_REQUIRED(env, mutex) (mutex) = (mutex) -#define MUTEX_REQUIRED_READ(env, mutex) (mutex) = (mutex) -#define MUTEX_WAIT(env, mutex, duration) (mutex) = (mutex) +#define MUTEX_IS_OWNED(env, mutex) 1 #endif /* + * Bulk initialization of mutexes in regions. + */ + +#define MUTEX_BULK_INIT(env, region, start, howmany) do { \ + DB_MUTEX *__mutexp; \ + db_mutex_t __i = start; \ + u_int32_t __n = howmany; \ + for (__mutexp = MUTEXP_SET(env, __i); \ + --__n > 0; \ + __mutexp = MUTEXP_SET(env, __i)) { \ + __mutexp->flags = 0; \ + __i = (F_ISSET(env, ENV_PRIVATE)) ? \ + ((uintptr_t)__mutexp + region->mutex_size) : __i + 1; \ + __mutexp->mutex_next_link = __i; \ + } \ + __mutexp->flags = 0; \ + __mutexp->mutex_next_link = MUTEX_INVALID; \ +} while (0) + +/* * Berkeley DB ports may require single-threading at places in the code. */ #ifdef HAVE_MUTEX_VXWORKS |