1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1996,2008 Oracle.  All rights reserved.
5 *
6 * $Id: mutex.h,v 12.31 2008/01/08 20:58:18 bostic Exp $
7 */
8
9#ifndef _DB_MUTEX_H_
10#define	_DB_MUTEX_H_
11
12#if defined(__cplusplus)
13extern "C" {
14#endif
15
16/*
17 * By default, spin 50 times per processor if fail to acquire a test-and-set
18 * mutex, we have anecdotal evidence it's a reasonable value.
19 */
20#define	MUTEX_SPINS_PER_PROCESSOR	50
21
22/*
23 * Mutexes are represented by unsigned, 32-bit integral values.  As the
24 * OOB value is 0, mutexes can be initialized by zero-ing out the memory
25 * in which they reside.
26 */
27#define	MUTEX_INVALID	0
28
29/*
30 * We track mutex allocations by ID.
31 */
32#define	MTX_APPLICATION		 1
33#define	MTX_DB_HANDLE		 2
34#define	MTX_ENV_DBLIST		 3
35#define	MTX_ENV_HANDLE		 4
36#define	MTX_ENV_REGION		 5
37#define	MTX_LOCK_REGION		 6
38#define	MTX_LOGICAL_LOCK	 7
39#define	MTX_LOG_FILENAME	 8
40#define	MTX_LOG_FLUSH		 9
41#define	MTX_LOG_HANDLE		10
42#define	MTX_LOG_REGION		11
43#define	MTX_MPOOLFILE_HANDLE	12
44#define	MTX_MPOOL_FH		13
45#define	MTX_MPOOL_FILE_BUCKET	14
46#define	MTX_MPOOL_HANDLE	15
47#define	MTX_MPOOL_HASH_BUCKET	16
48#define	MTX_MPOOL_IO		17
49#define	MTX_MPOOL_REGION	18
50#define	MTX_MUTEX_REGION	19
51#define	MTX_MUTEX_TEST		20
52#define	MTX_REP_CHKPT		21
53#define	MTX_REP_DATABASE	22
54#define	MTX_REP_EVENT		23
55#define	MTX_REP_REGION		24
56#define	MTX_SEQUENCE		25
57#define	MTX_TWISTER		26
58#define	MTX_TXN_ACTIVE		27
59#define	MTX_TXN_CHKPT		28
60#define	MTX_TXN_COMMIT		29
61#define	MTX_TXN_MVCC		30
62#define	MTX_TXN_REGION		31
63
64#define	MTX_MAX_ENTRY		31
65
66/* Redirect mutex calls to the correct functions. */
67#if !defined(HAVE_MUTEX_HYBRID) && (					\
68    defined(HAVE_MUTEX_PTHREADS) ||					\
69    defined(HAVE_MUTEX_SOLARIS_LWP) ||					\
70    defined(HAVE_MUTEX_UI_THREADS))
71#define	__mutex_init(a, b, c)		__db_pthread_mutex_init(a, b, c)
72#define	__mutex_lock(a, b)		__db_pthread_mutex_lock(a, b)
73#define	__mutex_unlock(a, b)		__db_pthread_mutex_unlock(a, b)
74#define	__mutex_destroy(a, b)		__db_pthread_mutex_destroy(a, b)
75#elif defined(HAVE_MUTEX_WIN32) || defined(HAVE_MUTEX_WIN32_GCC)
76#define	__mutex_init(a, b, c)		__db_win32_mutex_init(a, b, c)
77#define	__mutex_lock(a, b)		__db_win32_mutex_lock(a, b)
78#define	__mutex_unlock(a, b)		__db_win32_mutex_unlock(a, b)
79#define	__mutex_destroy(a, b)		__db_win32_mutex_destroy(a, b)
80#elif defined(HAVE_MUTEX_FCNTL)
81#define	__mutex_init(a, b, c)		__db_fcntl_mutex_init(a, b, c)
82#define	__mutex_lock(a, b)		__db_fcntl_mutex_lock(a, b)
83#define	__mutex_unlock(a, b)		__db_fcntl_mutex_unlock(a, b)
84#define	__mutex_destroy(a, b)		__db_fcntl_mutex_destroy(a, b)
85#else
86#define	__mutex_init(a, b, c)		__db_tas_mutex_init(a, b, c)
87#define	__mutex_lock(a, b)		__db_tas_mutex_lock(a, b)
88#define	__mutex_unlock(a, b)		__db_tas_mutex_unlock(a, b)
89#define	__mutex_destroy(a, b)		__db_tas_mutex_destroy(a, b)
90#endif
91
92/*
93 * Lock/unlock a mutex.  If the mutex was never required, the thread of
94 * control can proceed without it.
95 *
96 * We never fail to acquire or release a mutex without panicing.  Simplify
97 * the macros to always return a panic value rather than saving the actual
98 * return value of the mutex routine.
99 */
100#ifdef HAVE_MUTEX_SUPPORT
101#define	MUTEX_LOCK(dbenv, mutex) do {					\
102	if ((mutex) != MUTEX_INVALID &&					\
103	    __mutex_lock(dbenv, mutex) != 0)				\
104		return (DB_RUNRECOVERY);				\
105} while (0)
106#define	MUTEX_UNLOCK(dbenv, mutex) do {					\
107	if ((mutex) != MUTEX_INVALID &&					\
108	    __mutex_unlock(dbenv, mutex) != 0)				\
109		return (DB_RUNRECOVERY);				\
110} while (0)
111#else
112/*
113 * XXX
114 * There are calls to lock/unlock mutexes outside of #ifdef's -- replace
115 * the call with something the compiler can discard, but which will make
116 * if-then-else blocks work correctly.
117 */
118#define	MUTEX_LOCK(dbenv, mutex)					\
119	(mutex) = (mutex);
120#define	MUTEX_UNLOCK(dbenv, mutex)					\
121	(mutex) = (mutex);
122#endif
123
124/*
125 * Berkeley DB ports may require single-threading at places in the code.
126 */
127#ifdef HAVE_MUTEX_VXWORKS
128#include "taskLib.h"
129/*
130 * Use the taskLock() mutex to eliminate a race where two tasks are
131 * trying to initialize the global lock at the same time.
132 */
133#define	DB_BEGIN_SINGLE_THREAD do {					\
134	if (DB_GLOBAL(db_global_init))					\
135		(void)semTake(DB_GLOBAL(db_global_lock), WAIT_FOREVER);	\
136	else {								\
137		taskLock();						\
138		if (DB_GLOBAL(db_global_init)) {			\
139			taskUnlock();					\
140			(void)semTake(DB_GLOBAL(db_global_lock),	\
141			    WAIT_FOREVER);				\
142			continue;					\
143		}							\
144		DB_GLOBAL(db_global_lock) =				\
145		    semBCreate(SEM_Q_FIFO, SEM_EMPTY);			\
146		if (DB_GLOBAL(db_global_lock) != NULL)			\
147			DB_GLOBAL(db_global_init) = 1;			\
148		taskUnlock();						\
149	}								\
150} while (DB_GLOBAL(db_global_init) == 0)
151#define	DB_END_SINGLE_THREAD	(void)semGive(DB_GLOBAL(db_global_lock))
152#endif
153
154/*
155 * Single-threading defaults to a no-op.
156 */
157#ifndef DB_BEGIN_SINGLE_THREAD
158#define	DB_BEGIN_SINGLE_THREAD
159#endif
160#ifndef DB_END_SINGLE_THREAD
161#define	DB_END_SINGLE_THREAD
162#endif
163
164#if defined(__cplusplus)
165}
166#endif
167
168#include "dbinc_auto/mutex_ext.h"
169#endif /* !_DB_MUTEX_H_ */
170