summaryrefslogtreecommitdiff
path: root/src/dbinc/mutex.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/dbinc/mutex.h')
-rw-r--r--src/dbinc/mutex.h110
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