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