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