1*7c478bd9Sstevel@tonic-gate /*- 2*7c478bd9Sstevel@tonic-gate * See the file LICENSE for redistribution information. 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * Copyright (c) 1996, 1997, 1998 5*7c478bd9Sstevel@tonic-gate * Sleepycat Software. All rights reserved. 6*7c478bd9Sstevel@tonic-gate */ 7*7c478bd9Sstevel@tonic-gate 8*7c478bd9Sstevel@tonic-gate #include "config.h" 9*7c478bd9Sstevel@tonic-gate 10*7c478bd9Sstevel@tonic-gate #ifndef lint 11*7c478bd9Sstevel@tonic-gate static const char sccsid[] = "@(#)mutex.c 10.52 (Sleepycat) 11/8/98"; 12*7c478bd9Sstevel@tonic-gate #endif /* not lint */ 13*7c478bd9Sstevel@tonic-gate 14*7c478bd9Sstevel@tonic-gate #ifndef NO_SYSTEM_INCLUDES 15*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 16*7c478bd9Sstevel@tonic-gate 17*7c478bd9Sstevel@tonic-gate #include <errno.h> 18*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 19*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 20*7c478bd9Sstevel@tonic-gate #include <string.h> 21*7c478bd9Sstevel@tonic-gate #include <unistd.h> 22*7c478bd9Sstevel@tonic-gate #endif 23*7c478bd9Sstevel@tonic-gate 24*7c478bd9Sstevel@tonic-gate #include "db_int.h" 25*7c478bd9Sstevel@tonic-gate 26*7c478bd9Sstevel@tonic-gate #ifdef HAVE_SPINLOCKS 27*7c478bd9Sstevel@tonic-gate 28*7c478bd9Sstevel@tonic-gate #ifdef HAVE_FUNC_AIX 29*7c478bd9Sstevel@tonic-gate #define TSL_INIT(x) 30*7c478bd9Sstevel@tonic-gate #define TSL_SET(x) (!_check_lock(x, 0, 1)) 31*7c478bd9Sstevel@tonic-gate #define TSL_UNSET(x) _clear_lock(x, 0) 32*7c478bd9Sstevel@tonic-gate #endif 33*7c478bd9Sstevel@tonic-gate 34*7c478bd9Sstevel@tonic-gate #ifdef HAVE_ASSEM_MC68020_GCC 35*7c478bd9Sstevel@tonic-gate #include "68020.gcc" 36*7c478bd9Sstevel@tonic-gate #endif 37*7c478bd9Sstevel@tonic-gate 38*7c478bd9Sstevel@tonic-gate #if defined(HAVE_FUNC_MSEM) 39*7c478bd9Sstevel@tonic-gate /* 40*7c478bd9Sstevel@tonic-gate * !!! 41*7c478bd9Sstevel@tonic-gate * Do not remove the MSEM_IF_NOWAIT flag. The problem is that if a single 42*7c478bd9Sstevel@tonic-gate * process makes two msem_lock() calls in a row, the second one returns an 43*7c478bd9Sstevel@tonic-gate * error. We depend on the fact that we can lock against ourselves in the 44*7c478bd9Sstevel@tonic-gate * locking subsystem, where we set up a mutex so that we can block ourselves. 45*7c478bd9Sstevel@tonic-gate * Tested on OSF1 v4.0. 46*7c478bd9Sstevel@tonic-gate */ 47*7c478bd9Sstevel@tonic-gate #define TSL_INIT(x) (msem_init(x, MSEM_UNLOCKED) == NULL) 48*7c478bd9Sstevel@tonic-gate #define TSL_INIT_ERROR 1 49*7c478bd9Sstevel@tonic-gate #define TSL_SET(x) (!msem_lock(x, MSEM_IF_NOWAIT)) 50*7c478bd9Sstevel@tonic-gate #define TSL_UNSET(x) msem_unlock(x, 0) 51*7c478bd9Sstevel@tonic-gate #endif 52*7c478bd9Sstevel@tonic-gate 53*7c478bd9Sstevel@tonic-gate #ifdef HAVE_FUNC_RELIANT 54*7c478bd9Sstevel@tonic-gate #define TSL_INIT(x) initspin(x, 1) 55*7c478bd9Sstevel@tonic-gate #define TSL_SET(x) (cspinlock(x) == 0) 56*7c478bd9Sstevel@tonic-gate #define TSL_UNSET(x) spinunlock(x) 57*7c478bd9Sstevel@tonic-gate #endif 58*7c478bd9Sstevel@tonic-gate 59*7c478bd9Sstevel@tonic-gate #ifdef HAVE_FUNC_SGI 60*7c478bd9Sstevel@tonic-gate #define TSL_INIT(x) (init_lock(x) != 0) 61*7c478bd9Sstevel@tonic-gate #define TSL_INIT_ERROR 1 62*7c478bd9Sstevel@tonic-gate #define TSL_SET(x) (!acquire_lock(x)) 63*7c478bd9Sstevel@tonic-gate #define TSL_UNSET(x) release_lock(x) 64*7c478bd9Sstevel@tonic-gate #endif 65*7c478bd9Sstevel@tonic-gate 66*7c478bd9Sstevel@tonic-gate #ifdef HAVE_FUNC_SOLARIS 67*7c478bd9Sstevel@tonic-gate /* 68*7c478bd9Sstevel@tonic-gate * Semaphore calls don't work on Solaris 5.5. 69*7c478bd9Sstevel@tonic-gate * 70*7c478bd9Sstevel@tonic-gate * #define TSL_INIT(x) (sema_init(x, 1, USYNC_PROCESS, NULL) != 0) 71*7c478bd9Sstevel@tonic-gate * #define TSL_INIT_ERROR 1 72*7c478bd9Sstevel@tonic-gate * #define TSL_SET(x) (sema_wait(x) == 0) 73*7c478bd9Sstevel@tonic-gate * #define TSL_UNSET(x) sema_post(x) 74*7c478bd9Sstevel@tonic-gate */ 75*7c478bd9Sstevel@tonic-gate #define TSL_INIT(x) 76*7c478bd9Sstevel@tonic-gate #define TSL_SET(x) (_lock_try(x)) 77*7c478bd9Sstevel@tonic-gate #define TSL_UNSET(x) _lock_clear(x) 78*7c478bd9Sstevel@tonic-gate #endif 79*7c478bd9Sstevel@tonic-gate 80*7c478bd9Sstevel@tonic-gate #ifdef HAVE_FUNC_VMS 81*7c478bd9Sstevel@tonic-gate #include <builtins.h> 82*7c478bd9Sstevel@tonic-gate #ifdef __ALPHA 83*7c478bd9Sstevel@tonic-gate #define TSL_SET(tsl) (!__TESTBITSSI(tsl, 0)) 84*7c478bd9Sstevel@tonic-gate #else /* __VAX */ 85*7c478bd9Sstevel@tonic-gate #define TSL_SET(tsl) (!(int)_BBSSI(0, tsl)) 86*7c478bd9Sstevel@tonic-gate #endif 87*7c478bd9Sstevel@tonic-gate #define TSL_UNSET(tsl) (*(tsl) = 0) 88*7c478bd9Sstevel@tonic-gate #define TSL_INIT(tsl) TSL_UNSET(tsl) 89*7c478bd9Sstevel@tonic-gate #endif 90*7c478bd9Sstevel@tonic-gate 91*7c478bd9Sstevel@tonic-gate #ifdef HAVE_ASSEM_PARISC_GCC 92*7c478bd9Sstevel@tonic-gate #include "parisc.gcc" 93*7c478bd9Sstevel@tonic-gate #endif 94*7c478bd9Sstevel@tonic-gate 95*7c478bd9Sstevel@tonic-gate #ifdef HAVE_ASSEM_SCO_CC 96*7c478bd9Sstevel@tonic-gate #include "sco.cc" 97*7c478bd9Sstevel@tonic-gate #endif 98*7c478bd9Sstevel@tonic-gate 99*7c478bd9Sstevel@tonic-gate #ifdef HAVE_ASSEM_SPARC_GCC 100*7c478bd9Sstevel@tonic-gate #include "sparc.gcc" 101*7c478bd9Sstevel@tonic-gate #endif 102*7c478bd9Sstevel@tonic-gate 103*7c478bd9Sstevel@tonic-gate #ifdef HAVE_ASSEM_UTS4_CC 104*7c478bd9Sstevel@tonic-gate #define TSL_INIT(x) 105*7c478bd9Sstevel@tonic-gate #define TSL_SET(x) (!uts_lock(x, 1)) 106*7c478bd9Sstevel@tonic-gate #define TSL_UNSET(x) (*(x) = 0) 107*7c478bd9Sstevel@tonic-gate #endif 108*7c478bd9Sstevel@tonic-gate 109*7c478bd9Sstevel@tonic-gate #ifdef HAVE_ASSEM_X86_GCC 110*7c478bd9Sstevel@tonic-gate #include "x86.gcc" 111*7c478bd9Sstevel@tonic-gate #endif 112*7c478bd9Sstevel@tonic-gate 113*7c478bd9Sstevel@tonic-gate #ifdef WIN16 114*7c478bd9Sstevel@tonic-gate /* Win16 spinlocks are simple because we cannot possibly be preempted. */ 115*7c478bd9Sstevel@tonic-gate #define TSL_INIT(tsl) 116*7c478bd9Sstevel@tonic-gate #define TSL_SET(tsl) (*(tsl) = 1) 117*7c478bd9Sstevel@tonic-gate #define TSL_UNSET(tsl) (*(tsl) = 0) 118*7c478bd9Sstevel@tonic-gate #endif 119*7c478bd9Sstevel@tonic-gate 120*7c478bd9Sstevel@tonic-gate #if defined(_WIN32) 121*7c478bd9Sstevel@tonic-gate /* 122*7c478bd9Sstevel@tonic-gate * XXX 123*7c478bd9Sstevel@tonic-gate * DBDB this needs to be byte-aligned!! 124*7c478bd9Sstevel@tonic-gate */ 125*7c478bd9Sstevel@tonic-gate #define TSL_INIT(tsl) 126*7c478bd9Sstevel@tonic-gate #define TSL_SET(tsl) (!InterlockedExchange((PLONG)tsl, 1)) 127*7c478bd9Sstevel@tonic-gate #define TSL_UNSET(tsl) (*(tsl) = 0) 128*7c478bd9Sstevel@tonic-gate #endif 129*7c478bd9Sstevel@tonic-gate 130*7c478bd9Sstevel@tonic-gate #endif /* HAVE_SPINLOCKS */ 131*7c478bd9Sstevel@tonic-gate 132*7c478bd9Sstevel@tonic-gate /* 133*7c478bd9Sstevel@tonic-gate * __db_mutex_init -- 134*7c478bd9Sstevel@tonic-gate * Initialize a DB mutex structure. 135*7c478bd9Sstevel@tonic-gate * 136*7c478bd9Sstevel@tonic-gate * PUBLIC: int __db_mutex_init __P((db_mutex_t *, u_int32_t)); 137*7c478bd9Sstevel@tonic-gate */ 138*7c478bd9Sstevel@tonic-gate int 139*7c478bd9Sstevel@tonic-gate __db_mutex_init(mp, off) 140*7c478bd9Sstevel@tonic-gate db_mutex_t *mp; 141*7c478bd9Sstevel@tonic-gate u_int32_t off; 142*7c478bd9Sstevel@tonic-gate { 143*7c478bd9Sstevel@tonic-gate #ifdef DIAGNOSTIC 144*7c478bd9Sstevel@tonic-gate if ((ALIGNTYPE)mp & (MUTEX_ALIGNMENT - 1)) { 145*7c478bd9Sstevel@tonic-gate (void)fprintf(stderr, 146*7c478bd9Sstevel@tonic-gate "MUTEX ERROR: mutex NOT %d-byte aligned!\n", 147*7c478bd9Sstevel@tonic-gate MUTEX_ALIGNMENT); 148*7c478bd9Sstevel@tonic-gate abort(); 149*7c478bd9Sstevel@tonic-gate } 150*7c478bd9Sstevel@tonic-gate #endif 151*7c478bd9Sstevel@tonic-gate memset(mp, 0, sizeof(db_mutex_t)); 152*7c478bd9Sstevel@tonic-gate 153*7c478bd9Sstevel@tonic-gate #ifdef HAVE_SPINLOCKS 154*7c478bd9Sstevel@tonic-gate COMPQUIET(off, 0); 155*7c478bd9Sstevel@tonic-gate 156*7c478bd9Sstevel@tonic-gate #ifdef TSL_INIT_ERROR 157*7c478bd9Sstevel@tonic-gate if (TSL_INIT(&mp->tsl_resource)) 158*7c478bd9Sstevel@tonic-gate return (errno); 159*7c478bd9Sstevel@tonic-gate #else 160*7c478bd9Sstevel@tonic-gate TSL_INIT(&mp->tsl_resource); 161*7c478bd9Sstevel@tonic-gate #endif 162*7c478bd9Sstevel@tonic-gate mp->spins = __os_spin(); 163*7c478bd9Sstevel@tonic-gate #else 164*7c478bd9Sstevel@tonic-gate mp->off = off; 165*7c478bd9Sstevel@tonic-gate #endif 166*7c478bd9Sstevel@tonic-gate return (0); 167*7c478bd9Sstevel@tonic-gate } 168*7c478bd9Sstevel@tonic-gate 169*7c478bd9Sstevel@tonic-gate #define MS(n) ((n) * 1000) /* Milliseconds to micro-seconds. */ 170*7c478bd9Sstevel@tonic-gate #define SECOND (MS(1000)) /* A second's worth of micro-seconds. */ 171*7c478bd9Sstevel@tonic-gate 172*7c478bd9Sstevel@tonic-gate /* 173*7c478bd9Sstevel@tonic-gate * __db_mutex_lock 174*7c478bd9Sstevel@tonic-gate * Lock on a mutex, logically blocking if necessary. 175*7c478bd9Sstevel@tonic-gate * 176*7c478bd9Sstevel@tonic-gate * PUBLIC: int __db_mutex_lock __P((db_mutex_t *, int)); 177*7c478bd9Sstevel@tonic-gate */ 178*7c478bd9Sstevel@tonic-gate int 179*7c478bd9Sstevel@tonic-gate __db_mutex_lock(mp, fd) 180*7c478bd9Sstevel@tonic-gate db_mutex_t *mp; 181*7c478bd9Sstevel@tonic-gate int fd; 182*7c478bd9Sstevel@tonic-gate { 183*7c478bd9Sstevel@tonic-gate u_long usecs; 184*7c478bd9Sstevel@tonic-gate #ifdef HAVE_SPINLOCKS 185*7c478bd9Sstevel@tonic-gate int nspins; 186*7c478bd9Sstevel@tonic-gate #else 187*7c478bd9Sstevel@tonic-gate struct flock k_lock; 188*7c478bd9Sstevel@tonic-gate pid_t mypid; 189*7c478bd9Sstevel@tonic-gate int locked; 190*7c478bd9Sstevel@tonic-gate #endif 191*7c478bd9Sstevel@tonic-gate 192*7c478bd9Sstevel@tonic-gate if (!DB_GLOBAL(db_mutexlocks)) 193*7c478bd9Sstevel@tonic-gate return (0); 194*7c478bd9Sstevel@tonic-gate 195*7c478bd9Sstevel@tonic-gate #ifdef HAVE_SPINLOCKS 196*7c478bd9Sstevel@tonic-gate COMPQUIET(fd, 0); 197*7c478bd9Sstevel@tonic-gate 198*7c478bd9Sstevel@tonic-gate for (usecs = MS(1);;) { 199*7c478bd9Sstevel@tonic-gate /* Try and acquire the uncontested resource lock for N spins. */ 200*7c478bd9Sstevel@tonic-gate for (nspins = mp->spins; nspins > 0; --nspins) 201*7c478bd9Sstevel@tonic-gate if (TSL_SET(&mp->tsl_resource)) { 202*7c478bd9Sstevel@tonic-gate #ifdef DIAGNOSTIC 203*7c478bd9Sstevel@tonic-gate if (mp->pid != 0) { 204*7c478bd9Sstevel@tonic-gate (void)fprintf(stderr, 205*7c478bd9Sstevel@tonic-gate "MUTEX ERROR: __db_mutex_lock: lock currently locked\n"); 206*7c478bd9Sstevel@tonic-gate abort(); 207*7c478bd9Sstevel@tonic-gate } 208*7c478bd9Sstevel@tonic-gate mp->pid = getpid(); 209*7c478bd9Sstevel@tonic-gate #endif 210*7c478bd9Sstevel@tonic-gate if (usecs == MS(1)) 211*7c478bd9Sstevel@tonic-gate ++mp->mutex_set_nowait; 212*7c478bd9Sstevel@tonic-gate else 213*7c478bd9Sstevel@tonic-gate ++mp->mutex_set_wait; 214*7c478bd9Sstevel@tonic-gate return (0); 215*7c478bd9Sstevel@tonic-gate } 216*7c478bd9Sstevel@tonic-gate 217*7c478bd9Sstevel@tonic-gate /* Yield the processor; wait 1ms initially, up to 1 second. */ 218*7c478bd9Sstevel@tonic-gate __os_yield(usecs); 219*7c478bd9Sstevel@tonic-gate if ((usecs <<= 1) > SECOND) 220*7c478bd9Sstevel@tonic-gate usecs = SECOND; 221*7c478bd9Sstevel@tonic-gate } 222*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 223*7c478bd9Sstevel@tonic-gate 224*7c478bd9Sstevel@tonic-gate #else /* !HAVE_SPINLOCKS */ 225*7c478bd9Sstevel@tonic-gate 226*7c478bd9Sstevel@tonic-gate /* Initialize the lock. */ 227*7c478bd9Sstevel@tonic-gate k_lock.l_whence = SEEK_SET; 228*7c478bd9Sstevel@tonic-gate k_lock.l_start = mp->off; 229*7c478bd9Sstevel@tonic-gate k_lock.l_len = 1; 230*7c478bd9Sstevel@tonic-gate 231*7c478bd9Sstevel@tonic-gate for (locked = 0, mypid = getpid();;) { 232*7c478bd9Sstevel@tonic-gate /* 233*7c478bd9Sstevel@tonic-gate * Wait for the lock to become available; wait 1ms initially, 234*7c478bd9Sstevel@tonic-gate * up to 1 second. 235*7c478bd9Sstevel@tonic-gate */ 236*7c478bd9Sstevel@tonic-gate for (usecs = MS(1); mp->pid != 0;) { 237*7c478bd9Sstevel@tonic-gate __os_yield(usecs); 238*7c478bd9Sstevel@tonic-gate if ((usecs <<= 1) > SECOND) 239*7c478bd9Sstevel@tonic-gate usecs = SECOND; 240*7c478bd9Sstevel@tonic-gate } 241*7c478bd9Sstevel@tonic-gate 242*7c478bd9Sstevel@tonic-gate /* Acquire an exclusive kernel lock. */ 243*7c478bd9Sstevel@tonic-gate k_lock.l_type = F_WRLCK; 244*7c478bd9Sstevel@tonic-gate if (fcntl(fd, F_SETLKW, &k_lock)) 245*7c478bd9Sstevel@tonic-gate return (errno); 246*7c478bd9Sstevel@tonic-gate 247*7c478bd9Sstevel@tonic-gate /* If the resource tsl is still available, it's ours. */ 248*7c478bd9Sstevel@tonic-gate if (mp->pid == 0) { 249*7c478bd9Sstevel@tonic-gate locked = 1; 250*7c478bd9Sstevel@tonic-gate mp->pid = mypid; 251*7c478bd9Sstevel@tonic-gate } 252*7c478bd9Sstevel@tonic-gate 253*7c478bd9Sstevel@tonic-gate /* Release the kernel lock. */ 254*7c478bd9Sstevel@tonic-gate k_lock.l_type = F_UNLCK; 255*7c478bd9Sstevel@tonic-gate if (fcntl(fd, F_SETLK, &k_lock)) 256*7c478bd9Sstevel@tonic-gate return (errno); 257*7c478bd9Sstevel@tonic-gate 258*7c478bd9Sstevel@tonic-gate /* 259*7c478bd9Sstevel@tonic-gate * If we got the resource tsl we're done. 260*7c478bd9Sstevel@tonic-gate * 261*7c478bd9Sstevel@tonic-gate * !!! 262*7c478bd9Sstevel@tonic-gate * We can't check to see if the lock is ours, because we may 263*7c478bd9Sstevel@tonic-gate * be trying to block ourselves in the lock manager, and so 264*7c478bd9Sstevel@tonic-gate * the holder of the lock that's preventing us from getting 265*7c478bd9Sstevel@tonic-gate * the lock may be us! (Seriously.) 266*7c478bd9Sstevel@tonic-gate */ 267*7c478bd9Sstevel@tonic-gate if (locked) 268*7c478bd9Sstevel@tonic-gate break; 269*7c478bd9Sstevel@tonic-gate } 270*7c478bd9Sstevel@tonic-gate return (0); 271*7c478bd9Sstevel@tonic-gate #endif /* !HAVE_SPINLOCKS */ 272*7c478bd9Sstevel@tonic-gate } 273*7c478bd9Sstevel@tonic-gate 274*7c478bd9Sstevel@tonic-gate /* 275*7c478bd9Sstevel@tonic-gate * __db_mutex_unlock -- 276*7c478bd9Sstevel@tonic-gate * Release a lock. 277*7c478bd9Sstevel@tonic-gate * 278*7c478bd9Sstevel@tonic-gate * PUBLIC: int __db_mutex_unlock __P((db_mutex_t *, int)); 279*7c478bd9Sstevel@tonic-gate */ 280*7c478bd9Sstevel@tonic-gate int 281*7c478bd9Sstevel@tonic-gate __db_mutex_unlock(mp, fd) 282*7c478bd9Sstevel@tonic-gate db_mutex_t *mp; 283*7c478bd9Sstevel@tonic-gate int fd; 284*7c478bd9Sstevel@tonic-gate { 285*7c478bd9Sstevel@tonic-gate if (!DB_GLOBAL(db_mutexlocks)) 286*7c478bd9Sstevel@tonic-gate return (0); 287*7c478bd9Sstevel@tonic-gate 288*7c478bd9Sstevel@tonic-gate #ifdef DIAGNOSTIC 289*7c478bd9Sstevel@tonic-gate if (mp->pid == 0) { 290*7c478bd9Sstevel@tonic-gate (void)fprintf(stderr, 291*7c478bd9Sstevel@tonic-gate "MUTEX ERROR: __db_mutex_unlock: lock already unlocked\n"); 292*7c478bd9Sstevel@tonic-gate abort(); 293*7c478bd9Sstevel@tonic-gate } 294*7c478bd9Sstevel@tonic-gate #endif 295*7c478bd9Sstevel@tonic-gate 296*7c478bd9Sstevel@tonic-gate #ifdef HAVE_SPINLOCKS 297*7c478bd9Sstevel@tonic-gate COMPQUIET(fd, 0); 298*7c478bd9Sstevel@tonic-gate 299*7c478bd9Sstevel@tonic-gate #ifdef DIAGNOSTIC 300*7c478bd9Sstevel@tonic-gate mp->pid = 0; 301*7c478bd9Sstevel@tonic-gate #endif 302*7c478bd9Sstevel@tonic-gate 303*7c478bd9Sstevel@tonic-gate /* Release the resource tsl. */ 304*7c478bd9Sstevel@tonic-gate TSL_UNSET(&mp->tsl_resource); 305*7c478bd9Sstevel@tonic-gate #else 306*7c478bd9Sstevel@tonic-gate /* 307*7c478bd9Sstevel@tonic-gate * Release the resource tsl. We don't have to acquire any locks 308*7c478bd9Sstevel@tonic-gate * because processes trying to acquire the lock are checking for 309*7c478bd9Sstevel@tonic-gate * a pid of 0, not a specific value. 310*7c478bd9Sstevel@tonic-gate */ 311*7c478bd9Sstevel@tonic-gate mp->pid = 0; 312*7c478bd9Sstevel@tonic-gate #endif 313*7c478bd9Sstevel@tonic-gate return (0); 314*7c478bd9Sstevel@tonic-gate } 315