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.48 (Sleepycat) 5/23/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 * Should we not use MSEM_IF_NOWAIT and let the system block for us?
42 * I've no idea if this will block all threads in the process or not.
44 #define TSL_INIT(x) (msem_init(x, MSEM_UNLOCKED) == NULL)
45 #define TSL_INIT_ERROR 1
46 #define TSL_SET(x) (!msem_lock(x, MSEM_IF_NOWAIT))
47 #define TSL_UNSET(x) msem_unlock(x, 0)
50 #ifdef HAVE_FUNC_RELIANT
51 #define TSL_INIT(x) initspin(x, 1)
52 #define TSL_SET(x) (cspinlock(x) == 0)
53 #define TSL_UNSET(x) spinunlock(x)
57 #define TSL_INIT(x) (init_lock(x) != 0)
58 #define TSL_INIT_ERROR 1
59 #define TSL_SET(x) (!acquire_lock(x))
60 #define TSL_UNSET(x) release_lock(x)
63 #ifdef HAVE_FUNC_SOLARIS
65 * Semaphore calls don't work on Solaris 5.5.
67 * #define TSL_INIT(x) (sema_init(x, 1, USYNC_PROCESS, NULL) != 0)
68 * #define TSL_INIT_ERROR 1
69 * #define TSL_SET(x) (sema_wait(x) == 0)
70 * #define TSL_UNSET(x) sema_post(x)
73 #define TSL_SET(x) (_lock_try(x))
74 #define TSL_UNSET(x) _lock_clear(x)
77 #ifdef HAVE_ASSEM_PARISC_GCC
81 #ifdef HAVE_ASSEM_SCO_CC
85 #ifdef HAVE_ASSEM_SPARC_GCC
89 #ifdef HAVE_ASSEM_UTS4_CC
91 #define TSL_SET(x) (!uts_lock(x, 1))
92 #define TSL_UNSET(x) (*(x) = 0)
95 #ifdef HAVE_ASSEM_X86_GCC
100 /* Win16 spinlocks are simple because we cannot possibly be preempted. */
101 #define TSL_INIT(tsl)
102 #define TSL_SET(tsl) (*(tsl) = 1)
103 #define TSL_UNSET(tsl) (*(tsl) = 0)
109 * DBDB this needs to be byte-aligned!!
111 #define TSL_INIT(tsl)
112 #define TSL_SET(tsl) (!InterlockedExchange((PLONG)tsl, 1))
113 #define TSL_UNSET(tsl) (*(tsl) = 0)
116 #endif /* HAVE_SPINLOCKS */
120 * Initialize a DB mutex structure.
122 * PUBLIC: int __db_mutex_init __P((db_mutex_t *, u_int32_t));
125 __db_mutex_init(mp
, off
)
130 if ((ALIGNTYPE
)mp
& (MUTEX_ALIGNMENT
- 1)) {
131 (void)fprintf(stderr
,
132 "MUTEX ERROR: mutex NOT %d-byte aligned!\n",
137 memset(mp
, 0, sizeof(db_mutex_t
));
139 #ifdef HAVE_SPINLOCKS
142 #ifdef TSL_INIT_ERROR
143 if (TSL_INIT(&mp
->tsl_resource
))
146 TSL_INIT(&mp
->tsl_resource
);
148 mp
->spins
= __os_spin();
155 #define MS(n) ((n) * 1000) /* Milliseconds to micro-seconds. */
156 #define SECOND (MS(1000)) /* A second's worth of micro-seconds. */
160 * Lock on a mutex, logically blocking if necessary.
162 * PUBLIC: int __db_mutex_lock __P((db_mutex_t *, int));
165 __db_mutex_lock(mp
, fd
)
170 #ifdef HAVE_SPINLOCKS
178 if (!DB_GLOBAL(db_mutexlocks
))
181 #ifdef HAVE_SPINLOCKS
184 for (usecs
= MS(10);;) {
185 /* Try and acquire the uncontested resource lock for N spins. */
186 for (nspins
= mp
->spins
; nspins
> 0; --nspins
)
187 if (TSL_SET(&mp
->tsl_resource
)) {
190 (void)fprintf(stderr
,
191 "MUTEX ERROR: __db_mutex_lock: lock currently locked\n");
197 ++mp
->mutex_set_nowait
;
199 ++mp
->mutex_set_wait
;
203 /* Yield the processor; wait 10ms initially, up to 1 second. */
204 if (__db_yield
== NULL
|| __db_yield() != 0) {
205 (void)__db_sleep(0, usecs
);
206 if ((usecs
<<= 1) > SECOND
)
212 #else /* !HAVE_SPINLOCKS */
214 /* Initialize the lock. */
215 k_lock
.l_whence
= SEEK_SET
;
216 k_lock
.l_start
= mp
->off
;
219 for (locked
= 0, mypid
= getpid();;) {
221 * Wait for the lock to become available; wait 10ms initially,
224 for (usecs
= MS(10); mp
->pid
!= 0;)
225 if (__db_yield
== NULL
|| __db_yield() != 0) {
226 (void)__db_sleep(0, usecs
);
227 if ((usecs
<<= 1) > SECOND
)
231 /* Acquire an exclusive kernel lock. */
232 k_lock
.l_type
= F_WRLCK
;
233 if (fcntl(fd
, F_SETLKW
, &k_lock
))
236 /* If the resource tsl is still available, it's ours. */
242 /* Release the kernel lock. */
243 k_lock
.l_type
= F_UNLCK
;
244 if (fcntl(fd
, F_SETLK
, &k_lock
))
248 * If we got the resource tsl we're done.
251 * We can't check to see if the lock is ours, because we may
252 * be trying to block ourselves in the lock manager, and so
253 * the holder of the lock that's preventing us from getting
254 * the lock may be us! (Seriously.)
260 #endif /* !HAVE_SPINLOCKS */
264 * __db_mutex_unlock --
267 * PUBLIC: int __db_mutex_unlock __P((db_mutex_t *, int));
270 __db_mutex_unlock(mp
, fd
)
274 if (!DB_GLOBAL(db_mutexlocks
))
279 (void)fprintf(stderr
,
280 "MUTEX ERROR: __db_mutex_unlock: lock already unlocked\n");
285 #ifdef HAVE_SPINLOCKS
292 /* Release the resource tsl. */
293 TSL_UNSET(&mp
->tsl_resource
);
296 * Release the resource tsl. We don't have to acquire any locks
297 * because processes trying to acquire the lock are checking for
298 * a pid of 0, not a specific value.