From 54df2afaa61c6a03cbb4a33c9b90fa572b6d07b8 Mon Sep 17 00:00:00 2001 From: Jesse Morgan Date: Sat, 17 Dec 2016 21:28:53 -0800 Subject: Berkeley DB 4.8 with rust build script for linux. --- db-4.8.30/dbinc/mutex_int.h | 1073 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1073 insertions(+) create mode 100644 db-4.8.30/dbinc/mutex_int.h (limited to 'db-4.8.30/dbinc/mutex_int.h') 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 +#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 to -- 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 + +#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 +#include + +#define MUTEX_FIELDS \ + mutex_t mutex; /* Mutex. */ \ + cond_t cond; /* Condition variable. */ +#endif + +/********************************************************************* + * AIX C library functions. + *********************************************************************/ +#ifdef HAVE_MUTEX_AIX_CHECK_LOCK +#include +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 +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 +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 +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 +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 +#define MUTEX_MEMBAR(x) membar_enter() +#define MEMBAR_ENTER() membar_enter() +#define MEMBAR_EXIT() membar_exit() +#include +typedef lock_t tsl_t; + +/* + * The functions are declared in , 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 +#include +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 +#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 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_ */ -- cgit v1.2.3