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