2 * See the file LICENSE for redistribution information.
4 * Copyright (c) 1996, 1997, 1998
5 * Sleepycat Software. All rights reserved.
11 static const char sccsid
[] = "@(#)mutex.c 10.52 (Sleepycat) 11/8/98";
14 #ifndef NO_SYSTEM_INCLUDES
15 #include <sys/types.h>
30 #define TSL_SET(x) (!_check_lock(x, 0, 1))
31 #define TSL_UNSET(x) _clear_lock(x, 0)
34 #ifdef HAVE_ASSEM_MC68020_GCC
38 #if defined(HAVE_FUNC_MSEM)
41 * Do not remove the MSEM_IF_NOWAIT flag. The problem is that if a single
42 * process makes two msem_lock() calls in a row, the second one returns an
43 * error. We depend on the fact that we can lock against ourselves in the
44 * locking subsystem, where we set up a mutex so that we can block ourselves.
45 * Tested on OSF1 v4.0.
47 #define TSL_INIT(x) (msem_init(x, MSEM_UNLOCKED) == NULL)
48 #define TSL_INIT_ERROR 1
49 #define TSL_SET(x) (!msem_lock(x, MSEM_IF_NOWAIT))
50 #define TSL_UNSET(x) msem_unlock(x, 0)
53 #ifdef HAVE_FUNC_RELIANT
54 #define TSL_INIT(x) initspin(x, 1)
55 #define TSL_SET(x) (cspinlock(x) == 0)
56 #define TSL_UNSET(x) spinunlock(x)
60 #define TSL_INIT(x) (init_lock(x) != 0)
61 #define TSL_INIT_ERROR 1
62 #define TSL_SET(x) (!acquire_lock(x))
63 #define TSL_UNSET(x) release_lock(x)
66 #ifdef HAVE_FUNC_SOLARIS
68 * Semaphore calls don't work on Solaris 5.5.
70 * #define TSL_INIT(x) (sema_init(x, 1, USYNC_PROCESS, NULL) != 0)
71 * #define TSL_INIT_ERROR 1
72 * #define TSL_SET(x) (sema_wait(x) == 0)
73 * #define TSL_UNSET(x) sema_post(x)
76 #define TSL_SET(x) (_lock_try(x))
77 #define TSL_UNSET(x) _lock_clear(x)
83 #define TSL_SET(tsl) (!__TESTBITSSI(tsl, 0))
85 #define TSL_SET(tsl) (!(int)_BBSSI(0, tsl))
87 #define TSL_UNSET(tsl) (*(tsl) = 0)
88 #define TSL_INIT(tsl) TSL_UNSET(tsl)
91 #ifdef HAVE_ASSEM_PARISC_GCC
95 #ifdef HAVE_ASSEM_SCO_CC
99 #ifdef HAVE_ASSEM_SPARC_GCC
103 #ifdef HAVE_ASSEM_UTS4_CC
105 #define TSL_SET(x) (!uts_lock(x, 1))
106 #define TSL_UNSET(x) (*(x) = 0)
109 #ifdef HAVE_ASSEM_X86_GCC
114 /* Win16 spinlocks are simple because we cannot possibly be preempted. */
115 #define TSL_INIT(tsl)
116 #define TSL_SET(tsl) (*(tsl) = 1)
117 #define TSL_UNSET(tsl) (*(tsl) = 0)
123 * DBDB this needs to be byte-aligned!!
125 #define TSL_INIT(tsl)
126 #define TSL_SET(tsl) (!InterlockedExchange((PLONG)tsl, 1))
127 #define TSL_UNSET(tsl) (*(tsl) = 0)
130 #endif /* HAVE_SPINLOCKS */
134 * Initialize a DB mutex structure.
136 * PUBLIC: int __db_mutex_init __P((db_mutex_t *, u_int32_t));
139 __db_mutex_init(mp
, off
)
144 if ((ALIGNTYPE
)mp
& (MUTEX_ALIGNMENT
- 1)) {
145 (void)fprintf(stderr
,
146 "MUTEX ERROR: mutex NOT %d-byte aligned!\n",
151 memset(mp
, 0, sizeof(db_mutex_t
));
153 #ifdef HAVE_SPINLOCKS
156 #ifdef TSL_INIT_ERROR
157 if (TSL_INIT(&mp
->tsl_resource
))
160 TSL_INIT(&mp
->tsl_resource
);
162 mp
->spins
= __os_spin();
169 #define MS(n) ((n) * 1000) /* Milliseconds to micro-seconds. */
170 #define SECOND (MS(1000)) /* A second's worth of micro-seconds. */
174 * Lock on a mutex, logically blocking if necessary.
176 * PUBLIC: int __db_mutex_lock __P((db_mutex_t *, int));
179 __db_mutex_lock(mp
, fd
)
184 #ifdef HAVE_SPINLOCKS
192 if (!DB_GLOBAL(db_mutexlocks
))
195 #ifdef HAVE_SPINLOCKS
198 for (usecs
= MS(1);;) {
199 /* Try and acquire the uncontested resource lock for N spins. */
200 for (nspins
= mp
->spins
; nspins
> 0; --nspins
)
201 if (TSL_SET(&mp
->tsl_resource
)) {
204 (void)fprintf(stderr
,
205 "MUTEX ERROR: __db_mutex_lock: lock currently locked\n");
211 ++mp
->mutex_set_nowait
;
213 ++mp
->mutex_set_wait
;
217 /* Yield the processor; wait 1ms initially, up to 1 second. */
219 if ((usecs
<<= 1) > SECOND
)
224 #else /* !HAVE_SPINLOCKS */
226 /* Initialize the lock. */
227 k_lock
.l_whence
= SEEK_SET
;
228 k_lock
.l_start
= mp
->off
;
231 for (locked
= 0, mypid
= getpid();;) {
233 * Wait for the lock to become available; wait 1ms initially,
236 for (usecs
= MS(1); mp
->pid
!= 0;) {
238 if ((usecs
<<= 1) > SECOND
)
242 /* Acquire an exclusive kernel lock. */
243 k_lock
.l_type
= F_WRLCK
;
244 if (fcntl(fd
, F_SETLKW
, &k_lock
))
247 /* If the resource tsl is still available, it's ours. */
253 /* Release the kernel lock. */
254 k_lock
.l_type
= F_UNLCK
;
255 if (fcntl(fd
, F_SETLK
, &k_lock
))
259 * If we got the resource tsl we're done.
262 * We can't check to see if the lock is ours, because we may
263 * be trying to block ourselves in the lock manager, and so
264 * the holder of the lock that's preventing us from getting
265 * the lock may be us! (Seriously.)
271 #endif /* !HAVE_SPINLOCKS */
275 * __db_mutex_unlock --
278 * PUBLIC: int __db_mutex_unlock __P((db_mutex_t *, int));
281 __db_mutex_unlock(mp
, fd
)
285 if (!DB_GLOBAL(db_mutexlocks
))
290 (void)fprintf(stderr
,
291 "MUTEX ERROR: __db_mutex_unlock: lock already unlocked\n");
296 #ifdef HAVE_SPINLOCKS
303 /* Release the resource tsl. */
304 TSL_UNSET(&mp
->tsl_resource
);
307 * Release the resource tsl. We don't have to acquire any locks
308 * because processes trying to acquire the lock are checking for
309 * a pid of 0, not a specific value.