summaryrefslogtreecommitdiff
path: root/db-4.8.30/dbinc/mutex_int.h
diff options
context:
space:
mode:
authorJesse Morgan <jesse@jesterpm.net>2016-12-17 21:28:53 -0800
committerJesse Morgan <jesse@jesterpm.net>2016-12-17 21:28:53 -0800
commit54df2afaa61c6a03cbb4a33c9b90fa572b6d07b8 (patch)
tree18147b92b969d25ffbe61935fb63035cac820dd0 /db-4.8.30/dbinc/mutex_int.h
Berkeley DB 4.8 with rust build script for linux.
Diffstat (limited to 'db-4.8.30/dbinc/mutex_int.h')
-rw-r--r--db-4.8.30/dbinc/mutex_int.h1073
1 files changed, 1073 insertions, 0 deletions
diff --git a/db-4.8.30/dbinc/mutex_int.h b/db-4.8.30/dbinc/mutex_int.h
new file mode 100644
index 0000000..61edaf6
--- /dev/null
+++ b/db-4.8.30/dbinc/mutex_int.h
@@ -0,0 +1,1073 @@
+/*
+ * See the file LICENSE for redistribution information.
+ *
+ * Copyright (c) 1996-2009 Oracle. All rights reserved.
+ *
+ * $Id$
+ */
+
+#ifndef _DB_MUTEX_INT_H_
+#define _DB_MUTEX_INT_H_
+
+#include "dbinc/atomic.h"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*
+ * Mutexes and Shared Latches
+ *
+ * Mutexes may be test-and-set (spinning & yielding when busy),
+ * native versions (pthreads, WaitForSingleObject)
+ * or a hybrid which has the lower no-contention overhead of test-and-set
+ * mutexes, using operating system calls only to block and wakeup.
+ *
+ * Hybrid exclusive-only mutexes include a 'tas' field.
+ * Hybrid DB_MUTEX_SHARED latches also include a 'shared' field.
+ */
+
+/*********************************************************************
+ * POSIX.1 pthreads interface.
+ *********************************************************************/
+#if defined(HAVE_MUTEX_PTHREADS)
+/*
+ * Pthreads-based mutexes (exclusive-only) and latches (possibly shared)
+ * have the same MUTEX_FIELDS union. Different parts of the union are used
+ * depending on:
+ * - whether HAVE_SHARED_LATCHES is defined, and
+ * - if HAVE_SHARED_LATCHES, whether this particular instance of a mutex
+ * is a shared mutexDB_MUTEX_SHARED.
+ *
+ * The rwlock part of the union is used *only* for non-hybrid shared latches;
+ * in all other cases the mutex and cond fields are the only ones used.
+ *
+ * configuration & Who uses the field
+ * mutex
+ * mutex cond rwlock tas
+ * Native mutex y y
+ * Hybrid mutexes y y y
+ * Native sharedlatches y
+ * Hybrid sharedlatches y y y
+ *
+ * They all have a condition variable which is used only for
+ * DB_MUTEX_SELF_BLOCK waits.
+ *
+ * There can be no self-blocking shared latches: the pthread_cond_wait() would
+ * require getting a pthread_mutex_t, also it would not make sense.
+ */
+#define MUTEX_FIELDS \
+ union { \
+ struct { \
+ pthread_mutex_t mutex; /* Mutex */ \
+ pthread_cond_t cond; /* Condition variable */ \
+ } m; \
+ pthread_rwlock_t rwlock; /* Read/write lock */ \
+ } u;
+
+#if defined(HAVE_SHARED_LATCHES) && !defined(HAVE_MUTEX_HYBRID)
+#define RET_SET_PTHREAD_LOCK(mutexp, ret) do { \
+ if (F_ISSET(mutexp, DB_MUTEX_SHARED)) \
+ RET_SET((pthread_rwlock_wrlock(&(mutexp)->u.rwlock)), \
+ ret); \
+ else \
+ RET_SET((pthread_mutex_lock(&(mutexp)->u.m.mutex)), ret); \
+} while (0)
+#define RET_SET_PTHREAD_TRYLOCK(mutexp, ret) do { \
+ if (F_ISSET(mutexp, DB_MUTEX_SHARED)) \
+ RET_SET((pthread_rwlock_trywrlock(&(mutexp)->u.rwlock)), \
+ ret); \
+ else \
+ RET_SET((pthread_mutex_trylock(&(mutexp)->u.m.mutex)), \
+ ret); \
+} while (0)
+#else
+#define RET_SET_PTHREAD_LOCK(mutexp, ret) \
+ RET_SET(pthread_mutex_lock(&(mutexp)->u.m.mutex), ret);
+#define RET_SET_PTHREAD_TRYLOCK(mutexp, ret) \
+ RET_SET(pthread_mutex_trylock(&(mutexp)->u.m.mutex), ret);
+#endif
+#endif
+
+#ifdef HAVE_MUTEX_UI_THREADS
+#include <thread.h>
+#endif
+
+/*********************************************************************
+ * Solaris lwp threads interface.
+ *
+ * !!!
+ * We use LWP mutexes on Solaris instead of UI or POSIX mutexes (both of
+ * which are available), for two reasons. First, the Solaris C library
+ * includes versions of the both UI and POSIX thread mutex interfaces, but
+ * they are broken in that they don't support inter-process locking, and
+ * there's no way to detect it, e.g., calls to configure the mutexes for
+ * inter-process locking succeed without error. So, we use LWP mutexes so
+ * that we don't fail in fairly undetectable ways because the application
+ * wasn't linked with the appropriate threads library. Second, there were
+ * bugs in SunOS 5.7 (Solaris 7) where if an application loaded the C library
+ * before loading the libthread/libpthread threads libraries (e.g., by using
+ * dlopen to load the DB library), the pwrite64 interface would be translated
+ * into a call to pwrite and DB would drop core.
+ *********************************************************************/
+#ifdef HAVE_MUTEX_SOLARIS_LWP
+/*
+ * XXX
+ * Don't change <synch.h> to <sys/lwp.h> -- although lwp.h is listed in the
+ * Solaris manual page as the correct include to use, it causes the Solaris
+ * compiler on SunOS 2.6 to fail.
+ */
+#include <synch.h>
+
+#define MUTEX_FIELDS \
+ lwp_mutex_t mutex; /* Mutex. */ \
+ lwp_cond_t cond; /* Condition variable. */
+#endif
+
+/*********************************************************************
+ * Solaris/Unixware threads interface.
+ *********************************************************************/
+#ifdef HAVE_MUTEX_UI_THREADS
+#include <thread.h>
+#include <synch.h>
+
+#define MUTEX_FIELDS \
+ mutex_t mutex; /* Mutex. */ \
+ cond_t cond; /* Condition variable. */
+#endif
+
+/*********************************************************************
+ * AIX C library functions.
+ *********************************************************************/
+#ifdef HAVE_MUTEX_AIX_CHECK_LOCK
+#include <sys/atomic_op.h>
+typedef int tsl_t;
+
+#ifdef LOAD_ACTUAL_MUTEX_CODE
+#define MUTEX_INIT(x) 0
+#define MUTEX_SET(x) (!_check_lock(x, 0, 1))
+#define MUTEX_UNSET(x) _clear_lock(x, 0)
+#endif
+#endif
+
+/*********************************************************************
+ * Apple/Darwin library functions.
+ *********************************************************************/
+#ifdef HAVE_MUTEX_DARWIN_SPIN_LOCK_TRY
+typedef u_int32_t tsl_t;
+
+#ifdef LOAD_ACTUAL_MUTEX_CODE
+extern int _spin_lock_try(tsl_t *);
+extern void _spin_unlock(tsl_t *);
+#define MUTEX_SET(tsl) _spin_lock_try(tsl)
+#define MUTEX_UNSET(tsl) _spin_unlock(tsl)
+#define MUTEX_INIT(tsl) (MUTEX_UNSET(tsl), 0)
+#endif
+#endif
+
+/*********************************************************************
+ * General C library functions (msemaphore).
+ *
+ * !!!
+ * Check for HPPA as a special case, because it requires unusual alignment,
+ * and doesn't support semaphores in malloc(3) or shmget(2) memory.
+ *
+ * !!!
+ * Do not remove the MSEM_IF_NOWAIT flag. The problem is that if a single
+ * process makes two msem_lock() calls in a row, the second one returns an
+ * error. We depend on the fact that we can lock against ourselves in the
+ * locking subsystem, where we set up a mutex so that we can block ourselves.
+ * Tested on OSF1 v4.0.
+ *********************************************************************/
+#ifdef HAVE_MUTEX_HPPA_MSEM_INIT
+#define MUTEX_ALIGN 16
+#endif
+
+#if defined(HAVE_MUTEX_MSEM_INIT) || defined(HAVE_MUTEX_HPPA_MSEM_INIT)
+#include <sys/mman.h>
+typedef msemaphore tsl_t;
+
+#ifdef LOAD_ACTUAL_MUTEX_CODE
+#define MUTEX_INIT(x) (msem_init(x, MSEM_UNLOCKED) <= (msemaphore *)0)
+#define MUTEX_SET(x) (!msem_lock(x, MSEM_IF_NOWAIT))
+#define MUTEX_UNSET(x) msem_unlock(x, 0)
+#endif
+#endif
+
+/*********************************************************************
+ * Plan 9 library functions.
+ *********************************************************************/
+#ifdef HAVE_MUTEX_PLAN9
+typedef Lock tsl_t;
+
+#define MUTEX_INIT(x) (memset(x, 0, sizeof(Lock)), 0)
+#define MUTEX_SET(x) canlock(x)
+#define MUTEX_UNSET(x) unlock(x)
+#endif
+
+/*********************************************************************
+ * Reliant UNIX C library functions.
+ *********************************************************************/
+#ifdef HAVE_MUTEX_RELIANTUNIX_INITSPIN
+#include <ulocks.h>
+typedef spinlock_t tsl_t;
+
+#ifdef LOAD_ACTUAL_MUTEX_CODE
+#define MUTEX_INIT(x) (initspin(x, 1), 0)
+#define MUTEX_SET(x) (cspinlock(x) == 0)
+#define MUTEX_UNSET(x) spinunlock(x)
+#endif
+#endif
+
+/*********************************************************************
+ * General C library functions (POSIX 1003.1 sema_XXX).
+ *
+ * !!!
+ * Never selected by autoconfig in this release (semaphore calls are known
+ * to not work in Solaris 5.5).
+ *********************************************************************/
+#ifdef HAVE_MUTEX_SEMA_INIT
+#include <synch.h>
+typedef sema_t tsl_t;
+
+#ifdef LOAD_ACTUAL_MUTEX_CODE
+#define MUTEX_DESTROY(x) sema_destroy(x)
+#define MUTEX_INIT(x) (sema_init(x, 1, USYNC_PROCESS, NULL) != 0)
+#define MUTEX_SET(x) (sema_wait(x) == 0)
+#define MUTEX_UNSET(x) sema_post(x)
+#endif
+#endif
+
+/*********************************************************************
+ * SGI C library functions.
+ *********************************************************************/
+#ifdef HAVE_MUTEX_SGI_INIT_LOCK
+#include <abi_mutex.h>
+typedef abilock_t tsl_t;
+
+#ifdef LOAD_ACTUAL_MUTEX_CODE
+#define MUTEX_INIT(x) (init_lock(x) != 0)
+#define MUTEX_SET(x) (!acquire_lock(x))
+#define MUTEX_UNSET(x) release_lock(x)
+#endif
+#endif
+
+/*********************************************************************
+ * Solaris C library functions.
+ *
+ * !!!
+ * These are undocumented functions, but they're the only ones that work
+ * correctly as far as we know.
+ *********************************************************************/
+#ifdef HAVE_MUTEX_SOLARIS_LOCK_TRY
+#include <sys/atomic.h>
+#define MUTEX_MEMBAR(x) membar_enter()
+#define MEMBAR_ENTER() membar_enter()
+#define MEMBAR_EXIT() membar_exit()
+#include <sys/machlock.h>
+typedef lock_t tsl_t;
+
+/*
+ * The functions are declared in <sys/machlock.h>, but under #ifdef KERNEL.
+ * Re-declare them here to avoid warnings.
+ */
+extern int _lock_try(lock_t *);
+extern void _lock_clear(lock_t *);
+
+#ifdef LOAD_ACTUAL_MUTEX_CODE
+#define MUTEX_INIT(x) 0
+#define MUTEX_SET(x) _lock_try(x)
+#define MUTEX_UNSET(x) _lock_clear(x)
+#endif
+#endif
+
+/*********************************************************************
+ * VMS.
+ *********************************************************************/
+#ifdef HAVE_MUTEX_VMS
+#include <sys/mman.h>
+#include <builtins.h>
+typedef volatile unsigned char tsl_t;
+
+#ifdef LOAD_ACTUAL_MUTEX_CODE
+#ifdef __ALPHA
+#define MUTEX_SET(tsl) (!__TESTBITSSI(tsl, 0))
+#else /* __VAX */
+#define MUTEX_SET(tsl) (!(int)_BBSSI(0, tsl))
+#endif
+#define MUTEX_UNSET(tsl) (*(tsl) = 0)
+#define MUTEX_INIT(tsl) (MUTEX_UNSET(tsl), 0)
+#endif
+#endif
+
+/*********************************************************************
+ * VxWorks
+ * Use basic binary semaphores in VxWorks, as we currently do not need
+ * any special features. We do need the ability to single-thread the
+ * entire system, however, because VxWorks doesn't support the open(2)
+ * flag O_EXCL, the mechanism we normally use to single thread access
+ * when we're first looking for a DB environment.
+ *********************************************************************/
+#ifdef HAVE_MUTEX_VXWORKS
+#include "taskLib.h"
+typedef SEM_ID tsl_t;
+
+#ifdef LOAD_ACTUAL_MUTEX_CODE
+/*
+ * Uses of this MUTEX_SET() need to have a local 'nowait' variable,
+ * which determines whether to return right away when the semaphore
+ * is busy or to wait until it is available.
+ */
+#define MUTEX_SET(tsl) \
+ (semTake((*(tsl)), nowait ? NO_WAIT : WAIT_FOREVER) == OK)
+#define MUTEX_UNSET(tsl) (semGive((*tsl)))
+#define MUTEX_INIT(tsl) \
+ ((*(tsl) = semBCreate(SEM_Q_FIFO, SEM_FULL)) == NULL)
+#define MUTEX_DESTROY(tsl) semDelete(*tsl)
+#endif
+#endif
+
+/*********************************************************************
+ * Win16
+ *
+ * Win16 spinlocks are simple because we cannot possibly be preempted.
+ *
+ * !!!
+ * We should simplify this by always returning a no-need-to-lock lock
+ * when we initialize the mutex.
+ *********************************************************************/
+#ifdef HAVE_MUTEX_WIN16
+typedef unsigned int tsl_t;
+
+#ifdef LOAD_ACTUAL_MUTEX_CODE
+#define MUTEX_INIT(x) 0
+#define MUTEX_SET(tsl) (*(tsl) = 1)
+#define MUTEX_UNSET(tsl) (*(tsl) = 0)
+#endif
+#endif
+
+/*********************************************************************
+ * Win32 - always a hybrid mutex
+ *********************************************************************/
+#if defined(HAVE_MUTEX_WIN32) || defined(HAVE_MUTEX_WIN32_GCC)
+typedef LONG volatile tsl_t;
+#define MUTEX_FIELDS \
+ LONG nwaiters; \
+ u_int32_t id; /* ID used for creating events */ \
+
+#if defined(LOAD_ACTUAL_MUTEX_CODE)
+#define MUTEX_SET(tsl) (!InterlockedExchange((PLONG)tsl, 1))
+#define MUTEX_UNSET(tsl) InterlockedExchange((PLONG)tsl, 0)
+#define MUTEX_INIT(tsl) MUTEX_UNSET(tsl)
+
+/*
+ * From Intel's performance tuning documentation (and see SR #6975):
+ * ftp://download.intel.com/design/perftool/cbts/appnotes/sse2/w_spinlock.pdf
+ *
+ * "For this reason, it is highly recommended that you insert the PAUSE
+ * instruction into all spin-wait code immediately. Using the PAUSE
+ * instruction does not affect the correctness of programs on existing
+ * platforms, and it improves performance on Pentium 4 processor platforms."
+ */
+#ifdef HAVE_MUTEX_WIN32
+#if !defined(_WIN64) && !defined(DB_WINCE)
+#define MUTEX_PAUSE {__asm{_emit 0xf3}; __asm{_emit 0x90}}
+#endif
+#endif
+#ifdef HAVE_MUTEX_WIN32_GCC
+#define MUTEX_PAUSE __asm__ volatile ("rep; nop" : : );
+#endif
+#endif
+#endif
+
+/*********************************************************************
+ * 68K/gcc assembly.
+ *********************************************************************/
+#ifdef HAVE_MUTEX_68K_GCC_ASSEMBLY
+typedef unsigned char tsl_t;
+
+#ifdef LOAD_ACTUAL_MUTEX_CODE
+/* gcc/68K: 0 is clear, 1 is set. */
+#define MUTEX_SET(tsl) ({ \
+ register tsl_t *__l = (tsl); \
+ int __r; \
+ __asm__ volatile("tas %1; \n \
+ seq %0" \
+ : "=dm" (__r), "=m" (*__l) \
+ : "1" (*__l) \
+ ); \
+ __r & 1; \
+})
+
+#define MUTEX_UNSET(tsl) (*(tsl) = 0)
+#define MUTEX_INIT(tsl) (MUTEX_UNSET(tsl), 0)
+#endif
+#endif
+
+/*********************************************************************
+ * ALPHA/gcc assembly.
+ *********************************************************************/
+#ifdef HAVE_MUTEX_ALPHA_GCC_ASSEMBLY
+typedef u_int32_t tsl_t;
+
+#define MUTEX_ALIGN 4
+
+#ifdef LOAD_ACTUAL_MUTEX_CODE
+/*
+ * For gcc/alpha. Should return 0 if could not acquire the lock, 1 if
+ * lock was acquired properly.
+ */
+static inline int
+MUTEX_SET(tsl_t *tsl) {
+ register tsl_t *__l = tsl;
+ register tsl_t __r;
+ __asm__ volatile(
+ "1: ldl_l %0,%2\n"
+ " blbs %0,2f\n"
+ " or $31,1,%0\n"
+ " stl_c %0,%1\n"
+ " beq %0,3f\n"
+ " mb\n"
+ " br 3f\n"
+ "2: xor %0,%0\n"
+ "3:"
+ : "=&r"(__r), "=m"(*__l) : "1"(*__l) : "memory");
+ return __r;
+}
+
+/*
+ * Unset mutex. Judging by Alpha Architecture Handbook, the mb instruction
+ * might be necessary before unlocking
+ */
+static inline int
+MUTEX_UNSET(tsl_t *tsl) {
+ __asm__ volatile(" mb\n");
+ return *tsl = 0;
+}
+
+#define MUTEX_INIT(tsl) MUTEX_UNSET(tsl)
+#endif
+#endif
+
+/*********************************************************************
+ * Tru64/cc assembly.
+ *********************************************************************/
+#ifdef HAVE_MUTEX_TRU64_CC_ASSEMBLY
+typedef volatile u_int32_t tsl_t;
+
+#define MUTEX_ALIGN 4
+
+#ifdef LOAD_ACTUAL_MUTEX_CODE
+#include <alpha/builtins.h>
+#define MUTEX_SET(tsl) (__LOCK_LONG_RETRY((tsl), 1) != 0)
+#define MUTEX_UNSET(tsl) (__UNLOCK_LONG(tsl))
+
+#define MUTEX_INIT(tsl) (MUTEX_UNSET(tsl), 0)
+#endif
+#endif
+
+/*********************************************************************
+ * ARM/gcc assembly.
+ *********************************************************************/
+#ifdef HAVE_MUTEX_ARM_GCC_ASSEMBLY
+typedef unsigned char tsl_t;
+
+#ifdef LOAD_ACTUAL_MUTEX_CODE
+/* gcc/arm: 0 is clear, 1 is set. */
+#define MUTEX_SET(tsl) ({ \
+ int __r; \
+ __asm__ volatile( \
+ "swpb %0, %1, [%2]\n\t" \
+ "eor %0, %0, #1\n\t" \
+ : "=&r" (__r) \
+ : "r" (1), "r" (tsl) \
+ ); \
+ __r & 1; \
+})
+
+#define MUTEX_UNSET(tsl) (*(volatile tsl_t *)(tsl) = 0)
+#define MUTEX_INIT(tsl) (MUTEX_UNSET(tsl), 0)
+#endif
+#endif
+
+/*********************************************************************
+ * HPPA/gcc assembly.
+ *********************************************************************/
+#ifdef HAVE_MUTEX_HPPA_GCC_ASSEMBLY
+typedef u_int32_t tsl_t;
+
+#define MUTEX_ALIGN 16
+
+#ifdef LOAD_ACTUAL_MUTEX_CODE
+/*
+ * The PA-RISC has a "load and clear" instead of a "test and set" instruction.
+ * The 32-bit word used by that instruction must be 16-byte aligned. We could
+ * use the "aligned" attribute in GCC but that doesn't work for stack variables.
+ */
+#define MUTEX_SET(tsl) ({ \
+ register tsl_t *__l = (tsl); \
+ int __r; \
+ __asm__ volatile("ldcws 0(%1),%0" : "=r" (__r) : "r" (__l)); \
+ __r & 1; \
+})
+
+#define MUTEX_UNSET(tsl) (*(volatile tsl_t *)(tsl) = -1)
+#define MUTEX_INIT(tsl) (MUTEX_UNSET(tsl), 0)
+#endif
+#endif
+
+/*********************************************************************
+ * IA64/gcc assembly.
+ *********************************************************************/
+#ifdef HAVE_MUTEX_IA64_GCC_ASSEMBLY
+typedef volatile unsigned char tsl_t;
+
+#ifdef LOAD_ACTUAL_MUTEX_CODE
+/* gcc/ia64: 0 is clear, 1 is set. */
+#define MUTEX_SET(tsl) ({ \
+ register tsl_t *__l = (tsl); \
+ long __r; \
+ __asm__ volatile("xchg1 %0=%1,%2" : \
+ "=r"(__r), "+m"(*__l) : "r"(1)); \
+ __r ^ 1; \
+})
+
+/*
+ * Store through a "volatile" pointer so we get a store with "release"
+ * semantics.
+ */
+#define MUTEX_UNSET(tsl) (*(tsl_t *)(tsl) = 0)
+#define MUTEX_INIT(tsl) (MUTEX_UNSET(tsl), 0)
+#endif
+#endif
+
+/*********************************************************************
+ * PowerPC/gcc assembly.
+ *********************************************************************/
+#if defined(HAVE_MUTEX_PPC_GCC_ASSEMBLY)
+typedef u_int32_t tsl_t;
+
+#ifdef LOAD_ACTUAL_MUTEX_CODE
+/*
+ * The PowerPC does a sort of pseudo-atomic locking. You set up a
+ * 'reservation' on a chunk of memory containing a mutex by loading the
+ * mutex value with LWARX. If the mutex has an 'unlocked' (arbitrary)
+ * value, you then try storing into it with STWCX. If no other process or
+ * thread broke your 'reservation' by modifying the memory containing the
+ * mutex, then the STCWX succeeds; otherwise it fails and you try to get
+ * a reservation again.
+ *
+ * While mutexes are explicitly 4 bytes, a 'reservation' applies to an
+ * entire cache line, normally 32 bytes, aligned naturally. If the mutex
+ * lives near data that gets changed a lot, there's a chance that you'll
+ * see more broken reservations than you might otherwise. The only
+ * situation in which this might be a problem is if one processor is
+ * beating on a variable in the same cache block as the mutex while another
+ * processor tries to acquire the mutex. That's bad news regardless
+ * because of the way it bashes caches, but if you can't guarantee that a
+ * mutex will reside in a relatively quiescent cache line, you might
+ * consider padding the mutex to force it to live in a cache line by
+ * itself. No, you aren't guaranteed that cache lines are 32 bytes. Some
+ * embedded processors use 16-byte cache lines, while some 64-bit
+ * processors use 128-bit cache lines. But assuming a 32-byte cache line
+ * won't get you into trouble for now.
+ *
+ * If mutex locking is a bottleneck, then you can speed it up by adding a
+ * regular LWZ load before the LWARX load, so that you can test for the
+ * common case of a locked mutex without wasting cycles making a reservation.
+ *
+ * gcc/ppc: 0 is clear, 1 is set.
+ */
+static inline int
+MUTEX_SET(int *tsl) {
+ int __r;
+ __asm__ volatile (
+"0: \n\t"
+" lwarx %0,0,%1 \n\t"
+" cmpwi %0,0 \n\t"
+" bne- 1f \n\t"
+" stwcx. %1,0,%1 \n\t"
+" isync \n\t"
+" beq+ 2f \n\t"
+" b 0b \n\t"
+"1: \n\t"
+" li %1,0 \n\t"
+"2: \n\t"
+ : "=&r" (__r), "+r" (tsl)
+ :
+ : "cr0", "memory");
+ return (int)tsl;
+}
+
+static inline int
+MUTEX_UNSET(tsl_t *tsl) {
+ __asm__ volatile("sync" : : : "memory");
+ return *tsl = 0;
+}
+#define MUTEX_INIT(tsl) MUTEX_UNSET(tsl)
+#endif
+#endif
+
+/*********************************************************************
+ * OS/390 C.
+ *********************************************************************/
+#ifdef HAVE_MUTEX_S390_CC_ASSEMBLY
+typedef int tsl_t;
+
+#ifdef LOAD_ACTUAL_MUTEX_CODE
+/*
+ * cs() is declared in <stdlib.h> but is built in to the compiler.
+ * Must use LANGLVL(EXTENDED) to get its declaration.
+ */
+#define MUTEX_SET(tsl) (!cs(&zero, (tsl), 1))
+#define MUTEX_UNSET(tsl) (*(tsl) = 0)
+#define MUTEX_INIT(tsl) (MUTEX_UNSET(tsl), 0)
+#endif
+#endif
+
+/*********************************************************************
+ * S/390 32-bit assembly.
+ *********************************************************************/
+#ifdef HAVE_MUTEX_S390_GCC_ASSEMBLY
+typedef int tsl_t;
+
+#ifdef LOAD_ACTUAL_MUTEX_CODE
+/* gcc/S390: 0 is clear, 1 is set. */
+static inline int
+MUTEX_SET(tsl_t *tsl) { \
+ register tsl_t *__l = (tsl); \
+ int __r; \
+ __asm__ volatile( \
+ " la 1,%1\n" \
+ " lhi 0,1\n" \
+ " l %0,%1\n" \
+ "0: cs %0,0,0(1)\n" \
+ " jl 0b" \
+ : "=&d" (__r), "+m" (*__l) \
+ : : "0", "1", "cc"); \
+ return !__r; \
+}
+
+#define MUTEX_UNSET(tsl) (*(tsl) = 0)
+#define MUTEX_INIT(tsl) (MUTEX_UNSET(tsl), 0)
+#endif
+#endif
+
+/*********************************************************************
+ * SCO/cc assembly.
+ *********************************************************************/
+#ifdef HAVE_MUTEX_SCO_X86_CC_ASSEMBLY
+typedef unsigned char tsl_t;
+
+#ifdef LOAD_ACTUAL_MUTEX_CODE
+/*
+ * UnixWare has threads in libthread, but OpenServer doesn't (yet).
+ *
+ * cc/x86: 0 is clear, 1 is set.
+ */
+#if defined(__USLC__)
+asm int
+_tsl_set(void *tsl)
+{
+%mem tsl
+ movl tsl, %ecx
+ movl $1, %eax
+ lock
+ xchgb (%ecx),%al
+ xorl $1,%eax
+}
+#endif
+
+#define MUTEX_SET(tsl) _tsl_set(tsl)
+#define MUTEX_UNSET(tsl) (*(tsl) = 0)
+#define MUTEX_INIT(tsl) (MUTEX_UNSET(tsl), 0)
+#endif
+#endif
+
+/*********************************************************************
+ * Sparc/gcc assembly.
+ *********************************************************************/
+#ifdef HAVE_MUTEX_SPARC_GCC_ASSEMBLY
+typedef unsigned char tsl_t;
+
+#define MUTEX_ALIGN 8
+
+#ifdef LOAD_ACTUAL_MUTEX_CODE
+/*
+ * The ldstub instruction takes the location specified by its first argument
+ * (a register containing a memory address) and loads its contents into its
+ * second argument (a register) and atomically sets the contents the location
+ * specified by its first argument to a byte of 1s. (The value in the second
+ * argument is never read, but only overwritten.)
+ *
+ * Hybrid mutexes require membar #StoreLoad and #LoadStore ordering on multi-
+ * processor v9 systems.
+ *
+ * gcc/sparc: 0 is clear, 1 is set.
+ */
+#define MUTEX_SET(tsl) ({ \
+ register tsl_t *__l = (tsl); \
+ register tsl_t __r; \
+ __asm__ volatile \
+ ("ldstub [%1],%0; stbar" \
+ : "=r"( __r) : "r" (__l)); \
+ !__r; \
+})
+
+#define MUTEX_UNSET(tsl) (*(tsl) = 0, MUTEX_MEMBAR(tsl))
+#define MUTEX_INIT(tsl) (MUTEX_UNSET(tsl), 0)
+#define MUTEX_MEMBAR(x) \
+ ({ __asm__ volatile ("membar #StoreStore|#StoreLoad|#LoadStore"); })
+#define MEMBAR_ENTER() \
+ ({ __asm__ volatile ("membar #StoreStore|#StoreLoad"); })
+#define MEMBAR_EXIT() \
+ ({ __asm__ volatile ("membar #StoreStore|#LoadStore"); })
+#endif
+#endif
+
+/*********************************************************************
+ * UTS/cc assembly.
+ *********************************************************************/
+#ifdef HAVE_MUTEX_UTS_CC_ASSEMBLY
+typedef int tsl_t;
+
+#ifdef LOAD_ACTUAL_MUTEX_CODE
+#define MUTEX_INIT(x) 0
+#define MUTEX_SET(x) (!uts_lock(x, 1))
+#define MUTEX_UNSET(x) (*(x) = 0)
+#endif
+#endif
+
+/*********************************************************************
+ * MIPS/gcc assembly.
+ *********************************************************************/
+#ifdef HAVE_MUTEX_MIPS_GCC_ASSEMBLY
+typedef u_int32_t tsl_t;
+
+#define MUTEX_ALIGN 4
+
+#ifdef LOAD_ACTUAL_MUTEX_CODE
+/*
+ * For gcc/MIPS. Should return 0 if could not acquire the lock, 1 if
+ * lock was acquired properly.
+ */
+static inline int
+MUTEX_SET(tsl_t *tsl) {
+ register tsl_t *__l = tsl;
+ register tsl_t __r, __t;
+ __asm__ volatile(
+ " .set push \n"
+ " .set mips2 \n"
+ " .set noreorder \n"
+ " .set nomacro \n"
+ "1: ll %0, %3 \n"
+ " ori %2, %0, 1 \n"
+ " sc %2, %1 \n"
+ " beqzl %2, 1b \n"
+ " nop \n"
+ " andi %2, %0, 1 \n"
+ " sync \n"
+ " .set reorder \n"
+ " .set pop \n"
+ : "=&r" (__t), "=m" (*tsl), "=&r" (__r)
+ : "m" (*tsl)
+ : "memory");
+ return (!__r);
+}
+
+static inline void
+MUTEX_UNSET(tsl_t *tsl) {
+ __asm__ volatile(
+ " .set noreorder \n"
+ " sync \n"
+ " sw $0, %0 \n"
+ " .set reorder \n"
+ : "=m" (*tsl)
+ : "m" (*tsl)
+ : "memory");
+}
+
+#define MUTEX_INIT(tsl) (*(tsl) = 0)
+#endif
+#endif
+
+/*********************************************************************
+ * x86/gcc (32- and 64-bit) assembly.
+ *********************************************************************/
+#if defined(HAVE_MUTEX_X86_GCC_ASSEMBLY) || \
+ defined(HAVE_MUTEX_X86_64_GCC_ASSEMBLY)
+typedef volatile unsigned char tsl_t;
+
+#ifdef LOAD_ACTUAL_MUTEX_CODE
+/* gcc/x86: 0 is clear, 1 is set. */
+#define MUTEX_SET(tsl) ({ \
+ tsl_t __r; \
+ __asm__ volatile("movb $1, %b0\n\t" \
+ "xchgb %b0,%1" \
+ : "=&q" (__r) \
+ : "m" (*(tsl_t *)(tsl)) \
+ : "memory", "cc"); \
+ !__r; /* return 1 on success, 0 on failure */ \
+})
+
+#define MUTEX_UNSET(tsl) (*(tsl_t *)(tsl) = 0)
+#define MUTEX_INIT(tsl) (MUTEX_UNSET(tsl), 0)
+/*
+ * We need to pass a valid address to generate the memory barrier
+ * otherwise PURIFY will complain. Use something referenced recently
+ * and initialized.
+ */
+#if defined(HAVE_MUTEX_X86_GCC_ASSEMBLY)
+#define MUTEX_MEMBAR(addr) \
+ ({ __asm__ volatile ("lock; addl $0, %0" ::"m" (addr): "memory"); 1; })
+#else
+#define MUTEX_MEMBAR(addr) \
+ ({ __asm__ volatile ("mfence" ::: "memory"); 1; })
+#endif
+
+/*
+ * From Intel's performance tuning documentation (and see SR #6975):
+ * ftp://download.intel.com/design/perftool/cbts/appnotes/sse2/w_spinlock.pdf
+ *
+ * "For this reason, it is highly recommended that you insert the PAUSE
+ * instruction into all spin-wait code immediately. Using the PAUSE
+ * instruction does not affect the correctness of programs on existing
+ * platforms, and it improves performance on Pentium 4 processor platforms."
+ */
+#define MUTEX_PAUSE __asm__ volatile ("rep; nop" : : );
+#endif
+#endif
+
+/* End of operating system & hardware architecture-specific definitions */
+
+/*
+ * Mutex alignment defaults to sizeof(unsigned int).
+ *
+ * !!!
+ * Various systems require different alignments for mutexes (the worst we've
+ * seen so far is 16-bytes on some HP architectures). Malloc(3) is assumed
+ * to return reasonable alignment, all other mutex users must ensure proper
+ * alignment locally.
+ */
+#ifndef MUTEX_ALIGN
+#define MUTEX_ALIGN sizeof(unsigned int)
+#endif
+
+/*
+ * Mutex destruction defaults to a no-op.
+ */
+#ifndef MUTEX_DESTROY
+#define MUTEX_DESTROY(x)
+#endif
+
+/*
+ * Mutex pause defaults to a no-op.
+ */
+#ifndef MUTEX_PAUSE
+#define MUTEX_PAUSE
+#endif
+
+/*
+ * If no native atomic support is available then use mutexes to
+ * emulate atomic increment, decrement, and compare-and-exchange.
+ * The address of the atomic value selects which of a small number
+ * of mutexes to use to protect the updates.
+ * The number of mutexes should be somewhat larger than the number of
+ * processors in the system in order to minimize unnecessary contention.
+ * It defaults to 8 to handle most small (1-4) cpu systems, if it hasn't
+ * already been defined (e.g. in db_config.h)
+ */
+#if !defined(HAVE_ATOMIC_SUPPORT) && defined(HAVE_MUTEX_SUPPORT) && \
+ !defined(MAX_ATOMIC_MUTEXES)
+#define MAX_ATOMIC_MUTEXES 1
+#endif
+
+/*
+ * DB_MUTEXMGR --
+ * The mutex manager encapsulates the mutex system.
+ */
+struct __db_mutexmgr {
+ /* These fields are never updated after creation, so not protected. */
+ DB_ENV *dbenv; /* Environment */
+ REGINFO reginfo; /* Region information */
+
+ void *mutex_array; /* Base of the mutex array */
+};
+
+/* Macros to lock/unlock the mutex region as a whole. */
+#define MUTEX_SYSTEM_LOCK(dbenv) \
+ MUTEX_LOCK(dbenv, ((DB_MUTEXREGION *) \
+ (dbenv)->mutex_handle->reginfo.primary)->mtx_region)
+#define MUTEX_SYSTEM_UNLOCK(dbenv) \
+ MUTEX_UNLOCK(dbenv, ((DB_MUTEXREGION *) \
+ (dbenv)->mutex_handle->reginfo.primary)->mtx_region)
+
+/*
+ * DB_MUTEXREGION --
+ * The primary mutex data structure in the shared memory region.
+ */
+typedef struct __db_mutexregion {
+ /* These fields are initialized at create time and never modified. */
+ roff_t mutex_off_alloc;/* Offset of mutex array */
+ roff_t mutex_off; /* Adjusted offset of mutex array */
+ size_t mutex_size; /* Size of the aligned mutex */
+ roff_t thread_off; /* Offset of the thread area. */
+
+ db_mutex_t mtx_region; /* Region mutex. */
+
+ /* Protected using the region mutex. */
+ u_int32_t mutex_next; /* Next free mutex */
+
+#if !defined(HAVE_ATOMIC_SUPPORT) && defined(HAVE_MUTEX_SUPPORT)
+ /* Mutexes for emulating atomic operations. */
+ db_mutex_t mtx_atomic[MAX_ATOMIC_MUTEXES];
+#endif
+
+ DB_MUTEX_STAT stat; /* Mutex statistics */
+} DB_MUTEXREGION;
+
+#ifdef HAVE_MUTEX_SUPPORT
+struct __db_mutex_t { /* Mutex. */
+#ifdef MUTEX_FIELDS
+ MUTEX_FIELDS /* Opaque thread mutex structures. */
+#endif
+#ifndef HAVE_MUTEX_FCNTL
+#if defined(HAVE_MUTEX_HYBRID) || \
+ (defined(HAVE_SHARED_LATCHES) && !defined(HAVE_MUTEX_PTHREADS))
+ /*
+ * For hybrid and test-and-set shared latches it is a counter:
+ * 0 means it is free,
+ * -1 is exclusively locked,
+ * > 0 is the number of shared readers.
+ * Pthreads shared latches use pthread_rwlock instead.
+ */
+ db_atomic_t sharecount;
+ tsl_t tas;
+#elif !defined(MUTEX_FIELDS)
+ /*
+ * This is the Test and Set flag for exclusive latches (mutexes):
+ * there is a free value (often 0, 1, or -1) and a set value.
+ */
+ tsl_t tas;
+#endif
+#endif
+#ifdef HAVE_MUTEX_HYBRID
+ volatile u_int32_t wait; /* Count of waiters. */
+#endif
+ pid_t pid; /* Process owning mutex */
+ db_threadid_t tid; /* Thread owning mutex */
+
+ db_mutex_t mutex_next_link; /* Linked list of free mutexes. */
+
+#ifdef HAVE_STATISTICS
+ int alloc_id; /* Allocation ID. */
+
+ u_int32_t mutex_set_wait; /* Granted after wait. */
+ u_int32_t mutex_set_nowait; /* Granted without waiting. */
+#ifdef HAVE_SHARED_LATCHES
+ u_int32_t mutex_set_rd_wait; /* Granted shared lock after wait. */
+ u_int32_t mutex_set_rd_nowait; /* Granted shared lock w/out waiting. */
+#endif
+#ifdef HAVE_MUTEX_HYBRID
+ u_int32_t hybrid_wait;
+ u_int32_t hybrid_wakeup; /* for counting spurious wakeups */
+#endif
+#endif
+
+ /*
+ * A subset of the flag arguments for __mutex_alloc().
+ *
+ * Flags should be an unsigned integer even if it's not required by
+ * the possible flags values, getting a single byte on some machines
+ * is expensive, and the mutex structure is a MP hot spot.
+ */
+ volatile u_int32_t flags; /* MUTEX_XXX */
+};
+#endif
+
+/* Macro to get a reference to a specific mutex. */
+#define MUTEXP_SET(mtxmgr, indx) \
+ ((DB_MUTEX *)((u_int8_t *)mtxmgr->mutex_array + \
+ (indx) * ((DB_MUTEXREGION *)mtxmgr->reginfo.primary)->mutex_size))
+
+/* Inverse of the above: get the mutex index from a mutex pointer */
+#define MUTEXP_GET(mtxmgr, mutexp) \
+ (((u_int8_t *) (mutexp) - (u_int8_t *)mtxmgr->mutex_array) / \
+ ((DB_MUTEXREGION *)mtxmgr->reginfo.primary)->mutex_size)
+
+/*
+ * Check that a particular mutex is exclusively held at least by someone, not
+ * necessarily the current thread.
+ */
+#ifdef HAVE_MUTEX_SUPPORT
+#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_handle, mutex), DB_MUTEX_LOCKED))
+#else
+#define MUTEX_IS_OWNED(env, mutex) 0
+#endif
+
+#if defined(HAVE_MUTEX_HYBRID) || defined(DB_WIN32) || \
+ (defined(HAVE_SHARED_LATCHES) && !defined(HAVE_MUTEX_PTHREADS))
+#define MUTEXP_IS_BUSY(mutexp) \
+ (F_ISSET(mutexp, DB_MUTEX_SHARED) ? \
+ (atomic_read(&(mutexp)->sharecount) != 0) : \
+ F_ISSET(mutexp, DB_MUTEX_LOCKED))
+#define MUTEXP_BUSY_FIELD(mutexp) \
+ (F_ISSET(mutexp, DB_MUTEX_SHARED) ? \
+ (atomic_read(&(mutexp)->sharecount)) : (mutexp)->flags)
+#else
+/* Pthread_rwlocks don't have an low-cost 'is it being shared?' predicate. */
+#define MUTEXP_IS_BUSY(mutexp) (F_ISSET((mutexp), DB_MUTEX_LOCKED))
+#define MUTEXP_BUSY_FIELD(mutexp) ((mutexp)->flags)
+#endif
+
+#define MUTEX_IS_BUSY(env, mutex) \
+ (mutex == MUTEX_INVALID || !MUTEX_ON(env) || \
+ F_ISSET(env->dbenv, DB_ENV_NOLOCKING) || \
+ MUTEXP_IS_BUSY(MUTEXP_SET(env->mutex_handle, mutex)))
+
+#define MUTEX_REQUIRED(env, mutex) \
+ DB_ASSERT(env, MUTEX_IS_OWNED(env, mutex))
+
+#define MUTEX_REQUIRED_READ(env, mutex) \
+ DB_ASSERT(env, MUTEX_IS_OWNED(env, mutex) || MUTEX_IS_BUSY(env, mutex))
+
+/*
+ * Test and set (and thus hybrid) shared latches use compare & exchange
+ * to acquire; the others the mutex-setting primitive defined above.
+ */
+#ifdef LOAD_ACTUAL_MUTEX_CODE
+
+#if defined(HAVE_SHARED_LATCHES)
+/* This is the value of the 'sharecount' of an exclusively held tas latch.
+ * The particular value is not special; it is just unlikely to be caused
+ * by releasing or acquiring a shared latch too many times.
+ */
+#define MUTEX_SHARE_ISEXCLUSIVE (-1024)
+
+/*
+ * Get an exclusive lock on a possibly sharable latch. We use the native
+ * MUTEX_SET() operation for non-sharable latches; it usually is faster.
+ */
+#define MUTEXP_ACQUIRE(mutexp) \
+ (F_ISSET(mutexp, DB_MUTEX_SHARED) ? \
+ atomic_compare_exchange(env, \
+ &(mutexp)->sharecount, 0, MUTEX_SHARE_ISEXCLUSIVE) : \
+ MUTEX_SET(&(mutexp)->tas))
+#else
+#define MUTEXP_ACQUIRE(mutexp) MUTEX_SET(&(mutexp)->tas)
+#endif
+
+#ifndef MEMBAR_ENTER
+#define MEMBAR_ENTER()
+#define MEMBAR_EXIT()
+#endif
+
+#endif
+
+#if defined(__cplusplus)
+}
+#endif
+#endif /* !_DB_MUTEX_INT_H_ */