Update.
[glibc.git] / db2 / mutex / mutex.c
blobde0d0e23fe251512e2944844e3d3c49b7f72ca3c
1 /*-
2 * See the file LICENSE for redistribution information.
4 * Copyright (c) 1996, 1997, 1998
5 * Sleepycat Software. All rights reserved.
6 */
8 #include "config.h"
10 #ifndef lint
11 static const char sccsid[] = "@(#)mutex.c 10.48 (Sleepycat) 5/23/98";
12 #endif /* not lint */
14 #ifndef NO_SYSTEM_INCLUDES
15 #include <sys/types.h>
17 #include <errno.h>
18 #include <fcntl.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <unistd.h>
22 #endif
24 #include "db_int.h"
26 #ifdef HAVE_SPINLOCKS
28 #ifdef HAVE_FUNC_AIX
29 #define TSL_INIT(x)
30 #define TSL_SET(x) (!_check_lock(x, 0, 1))
31 #define TSL_UNSET(x) _clear_lock(x, 0)
32 #endif
34 #ifdef HAVE_ASSEM_MC68020_GCC
35 #include "68020.gcc"
36 #endif
38 #if defined(HAVE_FUNC_MSEM)
40 * XXX
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)
48 #endif
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)
54 #endif
56 #ifdef HAVE_FUNC_SGI
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)
61 #endif
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)
72 #define TSL_INIT(x)
73 #define TSL_SET(x) (_lock_try(x))
74 #define TSL_UNSET(x) _lock_clear(x)
75 #endif
77 #ifdef HAVE_ASSEM_PARISC_GCC
78 #include "parisc.gcc"
79 #endif
81 #ifdef HAVE_ASSEM_SCO_CC
82 #include "sco.cc"
83 #endif
85 #ifdef HAVE_ASSEM_SPARC_GCC
86 #include "sparc.gcc"
87 #endif
89 #ifdef HAVE_ASSEM_UTS4_CC
90 #define TSL_INIT(x)
91 #define TSL_SET(x) (!uts_lock(x, 1))
92 #define TSL_UNSET(x) (*(x) = 0)
93 #endif
95 #ifdef HAVE_ASSEM_X86_GCC
96 #include "x86.gcc"
97 #endif
99 #ifdef WIN16
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)
104 #endif
106 #if defined(_WIN32)
108 * XXX
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)
114 #endif
116 #endif /* HAVE_SPINLOCKS */
119 * __db_mutex_init --
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)
126 db_mutex_t *mp;
127 u_int32_t off;
129 #ifdef DIAGNOSTIC
130 if ((ALIGNTYPE)mp & (MUTEX_ALIGNMENT - 1)) {
131 (void)fprintf(stderr,
132 "MUTEX ERROR: mutex NOT %d-byte aligned!\n",
133 MUTEX_ALIGNMENT);
134 abort();
136 #endif
137 memset(mp, 0, sizeof(db_mutex_t));
139 #ifdef HAVE_SPINLOCKS
140 COMPQUIET(off, 0);
142 #ifdef TSL_INIT_ERROR
143 if (TSL_INIT(&mp->tsl_resource))
144 return (errno);
145 #else
146 TSL_INIT(&mp->tsl_resource);
147 #endif
148 mp->spins = __os_spin();
149 #else
150 mp->off = off;
151 #endif
152 return (0);
155 #define MS(n) ((n) * 1000) /* Milliseconds to micro-seconds. */
156 #define SECOND (MS(1000)) /* A second's worth of micro-seconds. */
159 * __db_mutex_lock
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)
166 db_mutex_t *mp;
167 int fd;
169 u_long usecs;
170 #ifdef HAVE_SPINLOCKS
171 int nspins;
172 #else
173 struct flock k_lock;
174 pid_t mypid;
175 int locked;
176 #endif
178 if (!DB_GLOBAL(db_mutexlocks))
179 return (0);
181 #ifdef HAVE_SPINLOCKS
182 COMPQUIET(fd, 0);
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)) {
188 #ifdef DIAGNOSTIC
189 if (mp->pid != 0) {
190 (void)fprintf(stderr,
191 "MUTEX ERROR: __db_mutex_lock: lock currently locked\n");
192 abort();
194 mp->pid = getpid();
195 #endif
196 if (usecs == MS(10))
197 ++mp->mutex_set_nowait;
198 else
199 ++mp->mutex_set_wait;
200 return (0);
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)
207 usecs = SECOND;
210 /* NOTREACHED */
212 #else /* !HAVE_SPINLOCKS */
214 /* Initialize the lock. */
215 k_lock.l_whence = SEEK_SET;
216 k_lock.l_start = mp->off;
217 k_lock.l_len = 1;
219 for (locked = 0, mypid = getpid();;) {
221 * Wait for the lock to become available; wait 10ms initially,
222 * up to 1 second.
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)
228 usecs = SECOND;
231 /* Acquire an exclusive kernel lock. */
232 k_lock.l_type = F_WRLCK;
233 if (fcntl(fd, F_SETLKW, &k_lock))
234 return (errno);
236 /* If the resource tsl is still available, it's ours. */
237 if (mp->pid == 0) {
238 locked = 1;
239 mp->pid = mypid;
242 /* Release the kernel lock. */
243 k_lock.l_type = F_UNLCK;
244 if (fcntl(fd, F_SETLK, &k_lock))
245 return (errno);
248 * If we got the resource tsl we're done.
250 * !!!
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.)
256 if (locked)
257 break;
259 return (0);
260 #endif /* !HAVE_SPINLOCKS */
264 * __db_mutex_unlock --
265 * Release a lock.
267 * PUBLIC: int __db_mutex_unlock __P((db_mutex_t *, int));
270 __db_mutex_unlock(mp, fd)
271 db_mutex_t *mp;
272 int fd;
274 if (!DB_GLOBAL(db_mutexlocks))
275 return (0);
277 #ifdef DIAGNOSTIC
278 if (mp->pid == 0) {
279 (void)fprintf(stderr,
280 "MUTEX ERROR: __db_mutex_unlock: lock already unlocked\n");
281 abort();
283 #endif
285 #ifdef HAVE_SPINLOCKS
286 COMPQUIET(fd, 0);
288 #ifdef DIAGNOSTIC
289 mp->pid = 0;
290 #endif
292 /* Release the resource tsl. */
293 TSL_UNSET(&mp->tsl_resource);
294 #else
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.
300 mp->pid = 0;
301 #endif
302 return (0);