1 /*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 1996, 1997, 1998, 1999 5 * Sleepycat Software. All rights reserved. 6 * 7 * @(#)mutex.h 11.6 (Sleepycat) 10/15/99 8 */ 9 10 /********************************************************************* 11 * POSIX.1 pthreads interface. 12 *********************************************************************/ 13 #ifdef HAVE_MUTEX_PTHREADS 14 #include <pthread.h> 15 16 #define MUTEX_FIELDS \ 17 pthread_mutex_t mutex; /* Mutex. */ \ 18 pthread_cond_t cond; /* Condition variable. */ 19 #endif 20 21 /********************************************************************* 22 * Solaris lwp threads interface. 23 * 24 * !!! 25 * We use LWP mutexes on Solaris instead of UI or POSIX mutexes (both of 26 * which are available), for two reasons. First, the Solaris C library 27 * includes versions of the both UI and POSIX thread mutex interfaces, but 28 * they are broken in that they don't support inter-process locking, and 29 * there's no way to detect it, e.g., calls to configure the mutexes for 30 * inter-process locking succeed without error. So, we use LWP mutexes so 31 * that we don't fail in fairly undetectable ways because the application 32 * wasn't linked with the appropriate threads library. Second, there were 33 * bugs in SunOS 5.7 (Solaris 7) where if an application loaded the C library 34 * before loading the libthread/libpthread threads libraries (e.g., by using 35 * dlopen to load the DB library), the pwrite64 interface would be translated 36 * into a call to pwrite and DB would drop core. 37 *********************************************************************/ 38 #ifdef HAVE_MUTEX_SOLARIS_LWP 39 #include <synch.h> 40 41 #define MUTEX_FIELDS \ 42 lwp_mutex_t mutex; /* Mutex. */ \ 43 lwp_cond_t cond; /* Condition variable. */ 44 #endif 45 46 /********************************************************************* 47 * Solaris/Unixware threads interface. 48 *********************************************************************/ 49 #ifdef HAVE_MUTEX_UI_THREADS 50 #include <thread.h> 51 #include <synch.h> 52 53 #define MUTEX_FIELDS \ 54 mutex_t mutex; /* Mutex. */ \ 55 cond_t cond; /* Condition variable. */ 56 #endif 57 58 /********************************************************************* 59 * AIX C library functions. 60 *********************************************************************/ 61 #ifdef HAVE_MUTEX_AIX_CHECK_LOCK 62 #include <sys/atomic_op.h> 63 typedef int tsl_t; 64 65 #define MUTEX_ALIGN sizeof(int) 66 #define MUTEX_SET(x) (!_check_lock(x, 0, 1)) 67 #define MUTEX_UNSET(x) _clear_lock(x, 0) 68 #endif 69 70 /********************************************************************* 71 * General C library functions (msemaphore). 72 * 73 * !!! 74 * Check for HPPA as a special case, because it requires unusual alignment, 75 * and doesn't support semaphores in malloc(3) or shmget(2) memory. 76 * 77 * !!! 78 * Do not remove the MSEM_IF_NOWAIT flag. The problem is that if a single 79 * process makes two msem_lock() calls in a row, the second one returns an 80 * error. We depend on the fact that we can lock against ourselves in the 81 * locking subsystem, where we set up a mutex so that we can block ourselves. 82 * Tested on OSF1 v4.0. 83 *********************************************************************/ 84 #ifdef HAVE_MUTEX_HPPA_MSEM_INIT 85 #define MUTEX_NO_MALLOC_LOCKS 86 #define MUTEX_NO_SHMGET_LOCKS 87 88 #define MUTEX_ALIGN 16 89 #endif 90 91 #if defined(HAVE_MUTEX_MSEM_INIT) || defined(HAVE_MUTEX_HPPA_MSEM_INIT) 92 #include <sys/mman.h> 93 typedef msemaphore tsl_t; 94 95 #ifndef MUTEX_ALIGN 96 #define MUTEX_ALIGN sizeof(int) 97 #endif 98 #define MUTEX_INIT(x) (msem_init(x, MSEM_UNLOCKED) == NULL) 99 #define MUTEX_SET(x) (!msem_lock(x, MSEM_IF_NOWAIT)) 100 #define MUTEX_UNSET(x) msem_unlock(x, 0) 101 #endif 102 103 /********************************************************************* 104 * MacOS. 105 * 106 * !!! 107 * We should simplify this by always returning a no-need-to-lock lock 108 * when we initialize the mutex. 109 *********************************************************************/ 110 #ifdef HAVE_MUTEX_MACOS 111 typedef unsigned char tsl_t; 112 113 #define MUTEX_INIT(x) 0 114 #endif 115 116 /********************************************************************* 117 * Reliant UNIX C library functions. 118 *********************************************************************/ 119 #ifdef HAVE_MUTEX_RELIANTUNIX_INITSPIN 120 #include <ulocks.h> 121 typedef spinlock_t tsl_t; 122 123 #define MUTEX_INIT(x) initspin(x, 1) 124 #define MUTEX_SET(x) (cspinlock(x) == 0) 125 #define MUTEX_UNSET(x) spinunlock(x) 126 #endif 127 128 /********************************************************************* 129 * General C library functions (POSIX 1003.1 sema_XXX). 130 * 131 * !!! 132 * Never selected by autoconfig in this release (semaphore calls are known 133 * to not work in Solaris 5.5). 134 *********************************************************************/ 135 #ifdef HAVE_MUTEX_SEMA_INIT 136 #include <synch.h> 137 typedef sema_t tsl_t; 138 139 #define MUTEX_ALIGN sizeof(int) 140 #define MUTEX_INIT(x) (sema_init(x, 1, USYNC_PROCESS, NULL) != 0) 141 #define MUTEX_SET(x) (sema_wait(x) == 0) 142 #define MUTEX_UNSET(x) sema_post(x) 143 #endif 144 145 /********************************************************************* 146 * SGI C library functions. 147 *********************************************************************/ 148 #ifdef HAVE_MUTEX_SGI_INIT_LOCK 149 #include <abi_mutex.h> 150 typedef abilock_t tsl_t; 151 152 #define MUTEX_ALIGN sizeof(int) 153 #define MUTEX_INIT(x) (init_lock(x) != 0) 154 #define MUTEX_SET(x) (!acquire_lock(x)) 155 #define MUTEX_UNSET(x) release_lock(x) 156 #endif 157 158 /********************************************************************* 159 * Solaris C library functions. 160 * 161 * !!! 162 * These are undocumented functions, but they're the only ones that work 163 * correctly as far as we know. 164 *********************************************************************/ 165 #ifdef HAVE_MUTEX_SOLARIS_LOCK_TRY 166 #include <sys/machlock.h> 167 typedef lock_t tsl_t; 168 169 #define MUTEX_ALIGN sizeof(int) 170 #define MUTEX_INIT(x) 0 171 #define MUTEX_SET(x) _lock_try(x) 172 #define MUTEX_UNSET(x) _lock_clear(x) 173 #endif 174 175 /********************************************************************* 176 * VMS. 177 *********************************************************************/ 178 #ifdef HAVE_MUTEX_VMS 179 #include <sys/mman.h>; 180 #include <builtins.h> 181 typedef unsigned char tsl_t; 182 183 #define MUTEX_ALIGN sizeof(unsigned int) 184 #ifdef __ALPHA 185 #define MUTEX_SET(tsl) (!__TESTBITSSI(tsl, 0)) 186 #else /* __VAX */ 187 #define MUTEX_SET(tsl) (!(int)_BBSSI(0, tsl)) 188 #endif 189 #define MUTEX_UNSET(tsl) (*(tsl) = 0) 190 #define MUTEX_INIT(tsl) MUTEX_UNSET(tsl) 191 #endif 192 193 /********************************************************************* 194 * Win16 195 * 196 * Win16 spinlocks are simple because we cannot possibly be preempted. 197 * 198 * !!! 199 * We should simplify this by always returning a no-need-to-lock lock 200 * when we initialize the mutex. 201 *********************************************************************/ 202 #ifdef HAVE_MUTEX_WIN16 203 typedef unsigned int tsl_t; 204 205 #define MUTEX_ALIGN sizeof(unsigned int) 206 #define MUTEX_INIT(x) 0 207 #define MUTEX_SET(tsl) (*(tsl) = 1) 208 #define MUTEX_UNSET(tsl) (*(tsl) = 0) 209 #endif 210 211 /********************************************************************* 212 * Win32 213 * 214 * XXX 215 * DBDB this needs to be byte-aligned!! 216 *********************************************************************/ 217 #ifdef HAVE_MUTEX_WIN32 218 typedef unsigned int tsl_t; 219 220 #define MUTEX_ALIGN sizeof(unsigned int) 221 #define MUTEX_INIT(x) 0 222 #define MUTEX_SET(tsl) (!InterlockedExchange((PLONG)tsl, 1)) 223 #define MUTEX_UNSET(tsl) (*(tsl) = 0) 224 #endif 225 226 /********************************************************************* 227 * 68K/gcc assembly. 228 *********************************************************************/ 229 #ifdef HAVE_MUTEX_68K_GCC_ASSEMBLY 230 typedef unsigned char tsl_t; 231 #endif 232 233 /********************************************************************* 234 * ALPHA/gcc assembly. 235 *********************************************************************/ 236 #ifdef HAVE_MUTEX_ALPHA_GCC_ASSEMBLY 237 typedef u_int32_t tsl_t; 238 239 #define MUTEX_ALIGN 4 240 #endif 241 242 /********************************************************************* 243 * HPPA/gcc assembly. 244 *********************************************************************/ 245 #ifdef HAVE_MUTEX_HPPA_GCC_ASSEMBLY 246 typedef u_int32_t tsl_t; 247 248 #define MUTEX_ALIGN 16 249 #endif 250 251 /********************************************************************* 252 * SCO/cc assembly. 253 *********************************************************************/ 254 #ifdef HAVE_MUTEX_SCO_X86_CC_ASSEMBLY 255 typedef unsigned char tsl_t; 256 #endif 257 258 /********************************************************************* 259 * Sparc/gcc assembly. 260 *********************************************************************/ 261 #ifdef HAVE_MUTEX_SPARC_GCC_ASSEMBLY 262 typedef unsigned char tsl_t; 263 #endif 264 265 /********************************************************************* 266 * UTS/cc assembly. 267 *********************************************************************/ 268 #ifdef HAVE_MUTEX_UTS_CC_ASSEMBLY 269 typedef int tsl_t; 270 271 #define MUTEX_ALIGN sizeof(int) 272 #define MUTEX_INIT(x) 0 273 #define MUTEX_SET(x) (!uts_lock(x, 1)) 274 #define MUTEX_UNSET(x) (*(x) = 0) 275 #endif 276 277 /********************************************************************* 278 * x86/gcc assembly. 279 *********************************************************************/ 280 #ifdef HAVE_MUTEX_X86_GCC_ASSEMBLY 281 typedef unsigned char tsl_t; 282 #endif 283 284 /* 285 * Mutex alignment defaults to one byte. 286 * 287 * !!! 288 * Various systems require different alignments for mutexes (the worst we've 289 * seen so far is 16-bytes on some HP architectures). Malloc(3) is assumed 290 * to return reasonable alignment, all other mutex users must ensure proper 291 * alignment locally. 292 */ 293 #ifndef MUTEX_ALIGN 294 #define MUTEX_ALIGN 1 295 #endif 296 297 #define MUTEX_IGNORE 0x001 /* Ignore, no lock required. */ 298 #define MUTEX_SELF_BLOCK 0x002 /* Must block self. */ 299 #define MUTEX_THREAD 0x004 /* Thread-only mutex. */ 300 301 /* Mutex. */ 302 struct __mutex_t { 303 #ifdef HAVE_MUTEX_THREADS 304 #ifdef MUTEX_FIELDS 305 MUTEX_FIELDS 306 #else 307 tsl_t tas; /* Test and set. */ 308 #endif 309 u_int32_t spins; /* Spins before block. */ 310 u_int32_t locked; /* !0 if locked. */ 311 #else 312 u_int32_t off; /* Byte offset to lock. */ 313 u_int32_t pid; /* Lock holder: 0 or process pid. */ 314 #endif 315 u_int32_t mutex_set_wait; /* Granted after wait. */ 316 u_int32_t mutex_set_nowait; /* Granted without waiting. */ 317 318 u_int8_t flags; /* MUTEX_XXX */ 319 }; 320 321 /* Redirect calls to the correct functions. */ 322 #ifdef HAVE_MUTEX_THREADS 323 #if defined(HAVE_MUTEX_PTHREADS) || defined(HAVE_MUTEX_SOLARIS_LWP) || defined(HAVE_MUTEX_UI_THREADS) 324 #define __db_mutex_init(a, b, c, d) CDB___db_pthread_mutex_init(a, b, d) 325 #define __db_mutex_lock(a, b) CDB___db_pthread_mutex_lock(a) 326 #define __db_mutex_unlock(a) CDB___db_pthread_mutex_unlock(a) 327 #else 328 #define __db_mutex_init(a, b, c, d) CDB___db_tas_mutex_init(a, b, d) 329 #define __db_mutex_lock(a, b) CDB___db_tas_mutex_lock(a) 330 #define __db_mutex_unlock(a) CDB___db_tas_mutex_unlock(a) 331 #endif 332 #else 333 #define __db_mutex_init(a, b, c, d) CDB___db_fcntl_mutex_init(a, b, c) 334 #define __db_mutex_lock(a, b) CDB___db_fcntl_mutex_lock(a, b) 335 #define __db_mutex_unlock(a) CDB___db_fcntl_mutex_unlock(a) 336 #endif 337 338 /* 339 * Lock/unlock a mutex. If the mutex was marked as uninteresting, the thread 340 * of control can proceed without it. 341 * 342 * If the lock is for threads-only, then it was optionally not allocated and 343 * file handles aren't necessary, as threaded applications aren't supported by 344 * fcntl(2) locking. 345 */ 346 #define MUTEX_LOCK(mp, fh) \ 347 if (!F_ISSET((MUTEX *)(mp), MUTEX_IGNORE)) \ 348 (void)__db_mutex_lock(mp, fh); 349 #define MUTEX_UNLOCK(mp) \ 350 if (!F_ISSET((MUTEX *)(mp), MUTEX_IGNORE)) \ 351 (void)__db_mutex_unlock(mp); 352 #define MUTEX_THREAD_LOCK(mp) \ 353 if (mp != NULL) \ 354 MUTEX_LOCK(mp, NULL) 355 #define MUTEX_THREAD_UNLOCK(mp) \ 356 if (mp != NULL) \ 357 MUTEX_UNLOCK(mp) 358 359 /* 360 * We use a single file descriptor for fcntl(2) locking, and (generally) the 361 * object's offset in a shared region as the byte that we're locking. So, 362 * there's a (remote) possibility that two objects might have the same offsets 363 * such that the locks could conflict, resulting in deadlock. To avoid this 364 * possibility, we offset the region offset by a small integer value, using a 365 * different offset for each subsystem's locks. Since all region objects are 366 * suitably aligned, the offset guarantees that we don't collide with another 367 * region's objects. 368 */ 369 #define DB_FCNTL_OFF_GEN 0 /* Everything else. */ 370 #define DB_FCNTL_OFF_LOCK 1 /* Lock subsystem offset. */ 371 #define DB_FCNTL_OFF_MPOOL 2 /* Mpool subsystem offset. */ 372