1/* 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 1996-2009 Oracle. All rights reserved. 5 * 6 * $Id$ 7 */ 8 9#ifndef _DB_MUTEX_H_ 10#define _DB_MUTEX_H_ 11 12#ifdef HAVE_MUTEX_SUPPORT 13/* The inlined trylock calls need access to the details of mutexes. */ 14#define LOAD_ACTUAL_MUTEX_CODE 15#include "dbinc/mutex_int.h" 16 17#ifndef HAVE_SHARED_LATCHES 18 #error "Shared latches are required in DB 4.8 and above" 19#endif 20#endif 21 22#if defined(__cplusplus) 23extern "C" { 24#endif 25 26/* 27 * By default, spin 50 times per processor if fail to acquire a test-and-set 28 * mutex, we have anecdotal evidence it's a reasonable value. 29 */ 30#define MUTEX_SPINS_PER_PROCESSOR 50 31 32/* 33 * Mutexes are represented by unsigned, 32-bit integral values. As the 34 * OOB value is 0, mutexes can be initialized by zero-ing out the memory 35 * in which they reside. 36 */ 37#define MUTEX_INVALID 0 38 39/* 40 * We track mutex allocations by ID. 41 */ 42#define MTX_APPLICATION 1 43#define MTX_ATOMIC_EMULATION 2 44#define MTX_DB_HANDLE 3 45#define MTX_ENV_DBLIST 4 46#define MTX_ENV_HANDLE 5 47#define MTX_ENV_REGION 6 48#define MTX_LOCK_REGION 7 49#define MTX_LOGICAL_LOCK 8 50#define MTX_LOG_FILENAME 9 51#define MTX_LOG_FLUSH 10 52#define MTX_LOG_HANDLE 11 53#define MTX_LOG_REGION 12 54#define MTX_MPOOLFILE_HANDLE 13 55#define MTX_MPOOL_BH 14 56#define MTX_MPOOL_FH 15 57#define MTX_MPOOL_FILE_BUCKET 16 58#define MTX_MPOOL_HANDLE 17 59#define MTX_MPOOL_HASH_BUCKET 18 60#define MTX_MPOOL_REGION 19 61#define MTX_MUTEX_REGION 20 62#define MTX_MUTEX_TEST 21 63#define MTX_REP_CHKPT 22 64#define MTX_REP_DATABASE 23 65#define MTX_REP_EVENT 24 66#define MTX_REP_REGION 25 67#define MTX_REPMGR 26 68#define MTX_SEQUENCE 27 69#define MTX_TWISTER 28 70#define MTX_TXN_ACTIVE 29 71#define MTX_TXN_CHKPT 30 72#define MTX_TXN_COMMIT 31 73#define MTX_TXN_MVCC 32 74#define MTX_TXN_REGION 33 75 76#define MTX_MAX_ENTRY 33 77 78/* Redirect mutex calls to the correct functions. */ 79#if !defined(HAVE_MUTEX_HYBRID) && ( \ 80 defined(HAVE_MUTEX_PTHREADS) || \ 81 defined(HAVE_MUTEX_SOLARIS_LWP) || \ 82 defined(HAVE_MUTEX_UI_THREADS)) 83#define __mutex_init(a, b, c) __db_pthread_mutex_init(a, b, c) 84#define __mutex_lock(a, b) __db_pthread_mutex_lock(a, b) 85#define __mutex_unlock(a, b) __db_pthread_mutex_unlock(a, b) 86#define __mutex_destroy(a, b) __db_pthread_mutex_destroy(a, b) 87#define __mutex_trylock(a, b) __db_pthread_mutex_trylock(a, b) 88/* 89 * These trylock versions do not support DB_ENV_FAILCHK. Callers which loop 90 * checking mutexes which are held by dead processes or threads might spin. 91 * These have ANSI-style definitions because this file can be included by 92 * C++ files, and extern "C" affects linkage only, not argument typing. 93 */ 94static inline int __db_pthread_mutex_trylock(ENV *env, db_mutex_t mutex) 95{ 96 int ret; 97 DB_MUTEX *mutexp; 98 if (!MUTEX_ON(env) || F_ISSET(env->dbenv, DB_ENV_NOLOCKING)) 99 return (0); 100 mutexp = MUTEXP_SET(env->mutex_handle, mutex); 101#ifdef HAVE_SHARED_LATCHES 102 if (F_ISSET(mutexp, DB_MUTEX_SHARED)) 103 ret = pthread_rwlock_trywrlock(&mutexp->u.rwlock); 104 else 105#endif 106 if ((ret = pthread_mutex_trylock(&mutexp->u.m.mutex)) == 0) 107 F_SET(mutexp, DB_MUTEX_LOCKED); 108 if (ret == EBUSY) 109 ret = DB_LOCK_NOTGRANTED; 110#ifdef HAVE_STATISTICS 111 if (ret == 0) 112 ++mutexp->mutex_set_nowait; 113#endif 114 return (ret); 115} 116#ifdef HAVE_SHARED_LATCHES 117#define __mutex_rdlock(a, b) __db_pthread_mutex_readlock(a, b) 118#define __mutex_tryrdlock(a, b) __db_pthread_mutex_tryreadlock(a, b) 119static inline int __db_pthread_mutex_tryreadlock(ENV *env, db_mutex_t mutex) 120{ 121 int ret; 122 DB_MUTEX *mutexp; 123 if (!MUTEX_ON(env) || F_ISSET(env->dbenv, DB_ENV_NOLOCKING)) 124 return (0); 125 mutexp = MUTEXP_SET(env->mutex_handle, mutex); 126 if (F_ISSET(mutexp, DB_MUTEX_SHARED)) 127 ret = pthread_rwlock_tryrdlock(&mutexp->u.rwlock); 128 else 129 return (EINVAL); 130 if (ret == EBUSY) 131 ret = DB_LOCK_NOTGRANTED; 132#ifdef HAVE_STATISTICS 133 if (ret == 0) 134 ++mutexp->mutex_set_rd_nowait; 135#endif 136 return (ret); 137} 138#endif 139#elif defined(HAVE_MUTEX_WIN32) || defined(HAVE_MUTEX_WIN32_GCC) 140#define __mutex_init(a, b, c) __db_win32_mutex_init(a, b, c) 141#define __mutex_lock(a, b) __db_win32_mutex_lock(a, b) 142#define __mutex_trylock(a, b) __db_win32_mutex_trylock(a, b) 143#define __mutex_unlock(a, b) __db_win32_mutex_unlock(a, b) 144#define __mutex_destroy(a, b) __db_win32_mutex_destroy(a, b) 145#ifdef HAVE_SHARED_LATCHES 146#define __mutex_rdlock(a, b) __db_win32_mutex_readlock(a, b) 147#define __mutex_tryrdlock(a, b) __db_win32_mutex_tryreadlock(a, b) 148#endif 149#elif defined(HAVE_MUTEX_FCNTL) 150#define __mutex_init(a, b, c) __db_fcntl_mutex_init(a, b, c) 151#define __mutex_lock(a, b) __db_fcntl_mutex_lock(a, b) 152#define __mutex_trylock(a, b) __db_fcntl_mutex_trylock(a, b) 153#define __mutex_unlock(a, b) __db_fcntl_mutex_unlock(a, b) 154#define __mutex_destroy(a, b) __db_fcntl_mutex_destroy(a, b) 155#else 156#define __mutex_init(a, b, c) __db_tas_mutex_init(a, b, c) 157#define __mutex_lock(a, b) __db_tas_mutex_lock(a, b) 158#define __mutex_trylock(a, b) __db_tas_mutex_trylock(a, b) 159#define __mutex_unlock(a, b) __db_tas_mutex_unlock(a, b) 160#define __mutex_destroy(a, b) __db_tas_mutex_destroy(a, b) 161#if defined(HAVE_SHARED_LATCHES) 162#define __mutex_rdlock(a, b) __db_tas_mutex_readlock(a, b) 163#define __mutex_tryrdlock(a,b) __db_tas_mutex_tryreadlock(a, b) 164#endif 165#endif 166 167/* 168 * When there is no method to get a shared latch, fall back to 169 * implementing __mutex_rdlock() as getting an exclusive one. 170 * This occurs either when !HAVE_SHARED_LATCHES or HAVE_MUTEX_FCNTL. 171 */ 172#ifndef __mutex_rdlock 173#define __mutex_rdlock(a, b) __mutex_lock(a, b) 174#endif 175#ifndef __mutex_tryrdlock 176#define __mutex_tryrdlock(a, b) __mutex_trylock(a, b) 177#endif 178 179/* 180 * Lock/unlock a mutex. If the mutex was never required, the thread of 181 * control can proceed without it. 182 * 183 * We never fail to acquire or release a mutex without panicing. Simplify 184 * the macros to always return a panic value rather than saving the actual 185 * return value of the mutex routine. 186 */ 187#ifdef HAVE_MUTEX_SUPPORT 188#define MUTEX_LOCK(env, mutex) do { \ 189 if ((mutex) != MUTEX_INVALID && \ 190 __mutex_lock(env, mutex) != 0) \ 191 return (DB_RUNRECOVERY); \ 192} while (0) 193 194/* 195 * Always check the return value of MUTEX_TRYLOCK()! Expect 0 on success, 196 * or DB_LOCK_NOTGRANTED, or possibly DB_RUNRECOVERY for failchk. 197 */ 198#define MUTEX_TRYLOCK(env, mutex) \ 199 (((mutex) == MUTEX_INVALID) ? 0 : __mutex_trylock(env, mutex)) 200 201/* 202 * Acquire a DB_MUTEX_SHARED "mutex" in shared mode. 203 */ 204#define MUTEX_READLOCK(env, mutex) do { \ 205 if ((mutex) != MUTEX_INVALID && \ 206 __mutex_rdlock(env, mutex) != 0) \ 207 return (DB_RUNRECOVERY); \ 208} while (0) 209#define MUTEX_TRY_READLOCK(env, mutex) \ 210 ((mutex) != MUTEX_INVALID ? __mutex_tryrdlock(env, mutex) : 0) 211 212#define MUTEX_UNLOCK(env, mutex) do { \ 213 if ((mutex) != MUTEX_INVALID && \ 214 __mutex_unlock(env, mutex) != 0) \ 215 return (DB_RUNRECOVERY); \ 216} while (0) 217#else 218/* 219 * There are calls to lock/unlock mutexes outside of #ifdef's -- replace 220 * the call with something the compiler can discard, but which will make 221 * if-then-else blocks work correctly. 222 */ 223#define MUTEX_LOCK(env, mutex) (mutex) = (mutex) 224#define MUTEX_TRYLOCK(env, mutex) (mutex) = (mutex) 225#define MUTEX_READLOCK(env, mutex) (mutex) = (mutex) 226#define MUTEX_TRY_READLOCK(env, mutex) (mutex) = (mutex) 227#define MUTEX_UNLOCK(env, mutex) (mutex) = (mutex) 228#define MUTEX_REQUIRED(env, mutex) (mutex) = (mutex) 229#define MUTEX_REQUIRED_READ(env, mutex) (mutex) = (mutex) 230#endif 231 232/* 233 * Berkeley DB ports may require single-threading at places in the code. 234 */ 235#ifdef HAVE_MUTEX_VXWORKS 236#include "taskLib.h" 237/* 238 * Use the taskLock() mutex to eliminate a race where two tasks are 239 * trying to initialize the global lock at the same time. 240 */ 241#define DB_BEGIN_SINGLE_THREAD do { \ 242 if (DB_GLOBAL(db_global_init)) \ 243 (void)semTake(DB_GLOBAL(db_global_lock), WAIT_FOREVER); \ 244 else { \ 245 taskLock(); \ 246 if (DB_GLOBAL(db_global_init)) { \ 247 taskUnlock(); \ 248 (void)semTake(DB_GLOBAL(db_global_lock), \ 249 WAIT_FOREVER); \ 250 continue; \ 251 } \ 252 DB_GLOBAL(db_global_lock) = \ 253 semBCreate(SEM_Q_FIFO, SEM_EMPTY); \ 254 if (DB_GLOBAL(db_global_lock) != NULL) \ 255 DB_GLOBAL(db_global_init) = 1; \ 256 taskUnlock(); \ 257 } \ 258} while (DB_GLOBAL(db_global_init) == 0) 259#define DB_END_SINGLE_THREAD (void)semGive(DB_GLOBAL(db_global_lock)) 260#endif 261 262/* 263 * Single-threading defaults to a no-op. 264 */ 265#ifndef DB_BEGIN_SINGLE_THREAD 266#define DB_BEGIN_SINGLE_THREAD 267#endif 268#ifndef DB_END_SINGLE_THREAD 269#define DB_END_SINGLE_THREAD 270#endif 271 272#if defined(__cplusplus) 273} 274#endif 275 276#include "dbinc_auto/mutex_ext.h" 277#endif /* !_DB_MUTEX_H_ */ 278