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.h305
1 files changed, 305 insertions, 0 deletions
diff --git a/src/dbinc/mutex.h b/src/dbinc/mutex.h
new file mode 100644
index 00000000..b699142c
--- /dev/null
+++ b/src/dbinc/mutex.h
@@ -0,0 +1,305 @@
+/*
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1996, 2012 Oracle and/or its affiliates. All rights reserved.
+ *
+ * $Id$
+ */
+
+#ifndef _DB_MUTEX_H_
+#define _DB_MUTEX_H_
+
+#ifdef HAVE_MUTEX_SUPPORT
+/* The inlined trylock calls need access to the details of mutexes. */
+#define LOAD_ACTUAL_MUTEX_CODE
+#include "dbinc/mutex_int.h"
+
+#ifndef HAVE_SHARED_LATCHES
+ #error "Shared latches are required in DB 4.8 and above"
+#endif
+#endif
+
+#if defined(__cplusplus)
+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.
+ */
+#define MUTEX_SPINS_PER_PROCESSOR 50
+
+/*
+ * Mutexes are represented by unsigned, 32-bit integral values. As the
+ * OOB value is 0, mutexes can be initialized by zero-ing out the memory
+ * in which they reside.
+ */
+#define MUTEX_INVALID 0
+
+/*
+ * We track mutex allocations by ID.
+ */
+#define MTX_APPLICATION 1
+#define MTX_ATOMIC_EMULATION 2
+#define MTX_DB_HANDLE 3
+#define MTX_ENV_DBLIST 4
+#define MTX_ENV_EXCLDBLIST 5
+#define MTX_ENV_HANDLE 6
+#define MTX_ENV_REGION 7
+#define MTX_LOCK_REGION 8
+#define MTX_LOGICAL_LOCK 9
+#define MTX_LOG_FILENAME 10
+#define MTX_LOG_FLUSH 11
+#define MTX_LOG_HANDLE 12
+#define MTX_LOG_REGION 13
+#define MTX_MPOOLFILE_HANDLE 14
+#define MTX_MPOOL_BH 15
+#define MTX_MPOOL_FH 16
+#define MTX_MPOOL_FILE_BUCKET 17
+#define MTX_MPOOL_HANDLE 18
+#define MTX_MPOOL_HASH_BUCKET 19
+#define MTX_MPOOL_REGION 20
+#define MTX_MUTEX_REGION 21
+#define MTX_MUTEX_TEST 22
+#define MTX_REP_CHKPT 23
+#define MTX_REP_DATABASE 24
+#define MTX_REP_DIAG 25
+#define MTX_REP_EVENT 26
+#define MTX_REP_REGION 27
+#define MTX_REP_START 28
+#define MTX_REP_WAITER 29
+#define MTX_REPMGR 30
+#define MTX_SEQUENCE 31
+#define MTX_TWISTER 32
+#define MTX_TCL_EVENTS 33
+#define MTX_TXN_ACTIVE 34
+#define MTX_TXN_CHKPT 35
+#define MTX_TXN_COMMIT 36
+#define MTX_TXN_MVCC 37
+#define MTX_TXN_REGION 38
+
+#define MTX_MAX_ENTRY 38
+
+/* The following macros are defined on some platforms, e.g. QNX. */
+#undef __mutex_init
+#undef __mutex_lock
+#undef __mutex_timedlock
+#undef __mutex_unlock
+#undef __mutex_destroy
+#undef __mutex_trylock
+
+/* Redirect mutex calls to the correct functions. */
+#if !defined(HAVE_MUTEX_HYBRID) && ( \
+ defined(HAVE_MUTEX_PTHREADS) || \
+ defined(HAVE_MUTEX_SOLARIS_LWP) || \
+ defined(HAVE_MUTEX_UI_THREADS))
+#define __mutex_init(a, b, c) __db_pthread_mutex_init(a, b, c)
+#define __mutex_lock(a, b) __db_pthread_mutex_lock(a, b, 0)
+#define __mutex_timedlock(a, b, c) __db_pthread_mutex_lock(a, b, c)
+#define __mutex_unlock(a, b) __db_pthread_mutex_unlock(a, b)
+#define __mutex_destroy(a, b) __db_pthread_mutex_destroy(a, b)
+#define __mutex_trylock(a, b) __db_pthread_mutex_trylock(a, b)
+/*
+ * These trylock versions do not support DB_ENV_FAILCHK. Callers which loop
+ * checking mutexes which are held by dead processes or threads might spin.
+ * These have ANSI-style definitions because this file can be included by
+ * C++ files, and extern "C" affects linkage only, not argument typing.
+ */
+static inline int __db_pthread_mutex_trylock(ENV *env, db_mutex_t mutex)
+{
+ int ret;
+ DB_MUTEX *mutexp;
+ if (!MUTEX_ON(env) || F_ISSET(env->dbenv, DB_ENV_NOLOCKING))
+ return (0);
+ mutexp = MUTEXP_SET(env, mutex);
+#ifdef HAVE_SHARED_LATCHES
+ if (F_ISSET(mutexp, DB_MUTEX_SHARED))
+ ret = pthread_rwlock_trywrlock(&mutexp->u.rwlock);
+ else
+#endif
+ ret = pthread_mutex_trylock(&mutexp->u.m.mutex);
+ if (ret == EBUSY)
+ ret = DB_LOCK_NOTGRANTED;
+ else if (ret == 0) {
+ F_SET(mutexp, DB_MUTEX_LOCKED);
+ env->dbenv->thread_id(env->dbenv, &mutexp->pid, &mutexp->tid);
+ STAT_INC(env,
+ mutex, set_nowait, mutexp->mutex_set_nowait, mutex);
+ }
+ return (ret);
+}
+#ifdef HAVE_SHARED_LATCHES
+#define __mutex_rdlock(a, b) __db_pthread_mutex_readlock(a, b)
+#define __mutex_tryrdlock(a, b) __db_pthread_mutex_tryreadlock(a, b)
+static inline int __db_pthread_mutex_tryreadlock(ENV *env, db_mutex_t mutex)
+{
+ int ret;
+ DB_MUTEX *mutexp;
+ if (!MUTEX_ON(env) || F_ISSET(env->dbenv, DB_ENV_NOLOCKING))
+ return (0);
+ mutexp = MUTEXP_SET(env, mutex);
+ if (F_ISSET(mutexp, DB_MUTEX_SHARED))
+ ret = pthread_rwlock_tryrdlock(&mutexp->u.rwlock);
+ else
+ return (EINVAL);
+ if (ret == EBUSY)
+ ret = DB_LOCK_NOTGRANTED;
+#ifdef HAVE_STATISTICS
+ if (ret == 0)
+ STAT_INC(env,
+ mutex, set_rd_nowait, mutexp->mutex_set_nowait, mutex);
+#endif
+ return (ret);
+}
+#endif
+#elif defined(HAVE_MUTEX_WIN32) || defined(HAVE_MUTEX_WIN32_GCC)
+#define __mutex_init(a, b, c) __db_win32_mutex_init(a, b, c)
+#define __mutex_lock(a, b) __db_win32_mutex_lock(a, b, 0)
+#define __mutex_timedlock(a, b, c) __db_win32_mutex_lock(a, b, c)
+#define __mutex_trylock(a, b) __db_win32_mutex_trylock(a, b)
+#define __mutex_unlock(a, b) __db_win32_mutex_unlock(a, b)
+#define __mutex_destroy(a, b) __db_win32_mutex_destroy(a, b)
+#ifdef HAVE_SHARED_LATCHES
+#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)
+#define __mutex_timedlock(a, b, c) __db_tas_mutex_lock(a, b, c)
+#define __mutex_trylock(a, b) __db_tas_mutex_trylock(a, b)
+#define __mutex_unlock(a, b) __db_tas_mutex_unlock(a, b)
+#define __mutex_destroy(a, b) __db_tas_mutex_destroy(a, b)
+#if defined(HAVE_SHARED_LATCHES)
+#define __mutex_rdlock(a, b) __db_tas_mutex_readlock(a, b)
+#define __mutex_tryrdlock(a,b) __db_tas_mutex_tryreadlock(a, b)
+#endif
+#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.
+ */
+#ifndef __mutex_rdlock
+#define __mutex_rdlock(a, b) __mutex_lock(a, b)
+#endif
+#ifndef __mutex_tryrdlock
+#define __mutex_tryrdlock(a, b) __mutex_trylock(a, b)
+#endif
+
+/*
+ * 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
+ * the macros to always return a panic value rather than saving the actual
+ * return value of the mutex routine.
+ */
+#ifdef HAVE_MUTEX_SUPPORT
+#define MUTEX_LOCK(env, mutex) do { \
+ if ((mutex) != MUTEX_INVALID && \
+ __mutex_lock(env, mutex) != 0) \
+ return (DB_RUNRECOVERY); \
+} while (0)
+
+/*
+ * Always check the return value of MUTEX_TRYLOCK()! Expect 0 on success,
+ * or DB_LOCK_NOTGRANTED, or possibly DB_RUNRECOVERY for failchk.
+ */
+#define MUTEX_TRYLOCK(env, mutex) \
+ (((mutex) == MUTEX_INVALID) ? 0 : __mutex_trylock(env, mutex))
+
+/*
+ * Acquire a DB_MUTEX_SHARED "mutex" in shared mode.
+ */
+#define MUTEX_READLOCK(env, mutex) do { \
+ if ((mutex) != MUTEX_INVALID && \
+ __mutex_rdlock(env, mutex) != 0) \
+ return (DB_RUNRECOVERY); \
+} while (0)
+#define MUTEX_TRY_READLOCK(env, mutex) \
+ ((mutex) != MUTEX_INVALID ? __mutex_tryrdlock(env, mutex) : 0)
+
+#define MUTEX_UNLOCK(env, mutex) do { \
+ if ((mutex) != MUTEX_INVALID && \
+ __mutex_unlock(env, mutex) != 0) \
+ 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); \
+} while (0)
+#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.
+ */
+#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)
+#endif
+
+/*
+ * Berkeley DB ports may require single-threading at places in the code.
+ */
+#ifdef HAVE_MUTEX_VXWORKS
+#include "taskLib.h"
+/*
+ * Use the taskLock() mutex to eliminate a race where two tasks are
+ * trying to initialize the global lock at the same time.
+ */
+#define DB_BEGIN_SINGLE_THREAD do { \
+ if (DB_GLOBAL(db_global_init)) \
+ (void)semTake(DB_GLOBAL(db_global_lock), WAIT_FOREVER); \
+ else { \
+ taskLock(); \
+ if (DB_GLOBAL(db_global_init)) { \
+ taskUnlock(); \
+ (void)semTake(DB_GLOBAL(db_global_lock), \
+ WAIT_FOREVER); \
+ continue; \
+ } \
+ DB_GLOBAL(db_global_lock) = \
+ semBCreate(SEM_Q_FIFO, SEM_EMPTY); \
+ if (DB_GLOBAL(db_global_lock) != NULL) \
+ DB_GLOBAL(db_global_init) = 1; \
+ taskUnlock(); \
+ } \
+} while (DB_GLOBAL(db_global_init) == 0)
+#define DB_END_SINGLE_THREAD (void)semGive(DB_GLOBAL(db_global_lock))
+#endif
+
+/*
+ * Single-threading defaults to a no-op.
+ */
+#ifndef DB_BEGIN_SINGLE_THREAD
+#define DB_BEGIN_SINGLE_THREAD
+#endif
+#ifndef DB_END_SINGLE_THREAD
+#define DB_END_SINGLE_THREAD
+#endif
+
+#if defined(__cplusplus)
+}
+#endif
+
+#include "dbinc_auto/mutex_ext.h"
+#endif /* !_DB_MUTEX_H_ */