1 | /*- |
---|
2 | * See the file LICENSE for redistribution information. |
---|
3 | * |
---|
4 | * Copyright (c) 1996-2002 |
---|
5 | * Sleepycat Software. All rights reserved. |
---|
6 | */ |
---|
7 | |
---|
8 | #include "db_config.h" |
---|
9 | |
---|
10 | #ifndef lint |
---|
11 | static const char revid[] = "Id: mut_tas.c,v 11.32 2002/05/07 18:42:21 bostic Exp "; |
---|
12 | #endif /* not lint */ |
---|
13 | |
---|
14 | #ifndef NO_SYSTEM_INCLUDES |
---|
15 | #include <sys/types.h> |
---|
16 | |
---|
17 | #include <stdlib.h> |
---|
18 | #include <string.h> |
---|
19 | #include <unistd.h> |
---|
20 | #endif |
---|
21 | |
---|
22 | /* |
---|
23 | * This is where we load in the actual test-and-set mutex code. |
---|
24 | */ |
---|
25 | #define LOAD_ACTUAL_MUTEX_CODE |
---|
26 | #include "db_int.h" |
---|
27 | |
---|
28 | /* |
---|
29 | * __db_tas_mutex_init -- |
---|
30 | * Initialize a DB_MUTEX. |
---|
31 | * |
---|
32 | * PUBLIC: int __db_tas_mutex_init __P((DB_ENV *, DB_MUTEX *, u_int32_t)); |
---|
33 | */ |
---|
34 | int |
---|
35 | __db_tas_mutex_init(dbenv, mutexp, flags) |
---|
36 | DB_ENV *dbenv; |
---|
37 | DB_MUTEX *mutexp; |
---|
38 | u_int32_t flags; |
---|
39 | { |
---|
40 | u_int32_t save; |
---|
41 | |
---|
42 | /* Check alignment. */ |
---|
43 | DB_ASSERT(((db_alignp_t)mutexp & (MUTEX_ALIGN - 1)) == 0); |
---|
44 | |
---|
45 | /* |
---|
46 | * The only setting/checking of the MUTEX_MPOOL flags is in the mutex |
---|
47 | * mutex allocation code (__db_mutex_alloc/free). Preserve only that |
---|
48 | * flag. This is safe because even if this flag was never explicitly |
---|
49 | * set, but happened to be set in memory, it will never be checked or |
---|
50 | * acted upon. |
---|
51 | */ |
---|
52 | save = F_ISSET(mutexp, MUTEX_MPOOL); |
---|
53 | memset(mutexp, 0, sizeof(*mutexp)); |
---|
54 | F_SET(mutexp, save); |
---|
55 | |
---|
56 | /* |
---|
57 | * If this is a thread lock or the process has told us that there are |
---|
58 | * no other processes in the environment, use thread-only locks, they |
---|
59 | * are faster in some cases. |
---|
60 | * |
---|
61 | * This is where we decide to ignore locks we don't need to set -- if |
---|
62 | * the application isn't threaded, there aren't any threads to block. |
---|
63 | */ |
---|
64 | if (LF_ISSET(MUTEX_THREAD) || F_ISSET(dbenv, DB_ENV_PRIVATE)) { |
---|
65 | if (!F_ISSET(dbenv, DB_ENV_THREAD)) { |
---|
66 | F_SET(mutexp, MUTEX_IGNORE); |
---|
67 | return (0); |
---|
68 | } |
---|
69 | } |
---|
70 | |
---|
71 | /* Initialize the lock. */ |
---|
72 | if (MUTEX_INIT(&mutexp->tas)) |
---|
73 | return (__os_get_errno()); |
---|
74 | |
---|
75 | mutexp->spins = __os_spin(dbenv); |
---|
76 | #ifdef HAVE_MUTEX_SYSTEM_RESOURCES |
---|
77 | mutexp->reg_off = INVALID_ROFF; |
---|
78 | #endif |
---|
79 | F_SET(mutexp, MUTEX_INITED); |
---|
80 | |
---|
81 | return (0); |
---|
82 | } |
---|
83 | |
---|
84 | /* |
---|
85 | * __db_tas_mutex_lock |
---|
86 | * Lock on a mutex, logically blocking if necessary. |
---|
87 | * |
---|
88 | * PUBLIC: int __db_tas_mutex_lock __P((DB_ENV *, DB_MUTEX *)); |
---|
89 | */ |
---|
90 | int |
---|
91 | __db_tas_mutex_lock(dbenv, mutexp) |
---|
92 | DB_ENV *dbenv; |
---|
93 | DB_MUTEX *mutexp; |
---|
94 | { |
---|
95 | u_long ms; |
---|
96 | int nspins; |
---|
97 | |
---|
98 | if (F_ISSET(dbenv, DB_ENV_NOLOCKING) || F_ISSET(mutexp, MUTEX_IGNORE)) |
---|
99 | return (0); |
---|
100 | |
---|
101 | ms = 1; |
---|
102 | |
---|
103 | loop: /* Attempt to acquire the resource for N spins. */ |
---|
104 | for (nspins = mutexp->spins; nspins > 0; --nspins) { |
---|
105 | #ifdef HAVE_MUTEX_HPPA_MSEM_INIT |
---|
106 | relock: |
---|
107 | #endif |
---|
108 | if (!MUTEX_SET(&mutexp->tas)) |
---|
109 | continue; |
---|
110 | #ifdef HAVE_MUTEX_HPPA_MSEM_INIT |
---|
111 | /* |
---|
112 | * HP semaphores are unlocked automatically when a holding |
---|
113 | * process exits. If the mutex appears to be locked |
---|
114 | * (mutexp->locked != 0) but we got here, assume this has |
---|
115 | * happened. Stick our own pid into mutexp->locked and |
---|
116 | * lock again. (The default state of the mutexes used to |
---|
117 | * block in __lock_get_internal is locked, so exiting with |
---|
118 | * a locked mutex is reasonable behavior for a process that |
---|
119 | * happened to initialize or use one of them.) |
---|
120 | */ |
---|
121 | if (mutexp->locked != 0) { |
---|
122 | __os_id(&mutexp->locked); |
---|
123 | goto relock; |
---|
124 | } |
---|
125 | /* |
---|
126 | * If we make it here, locked == 0, the diagnostic won't fire, |
---|
127 | * and we were really unlocked by someone calling the |
---|
128 | * DB mutex unlock function. |
---|
129 | */ |
---|
130 | #endif |
---|
131 | #ifdef DIAGNOSTIC |
---|
132 | if (mutexp->locked != 0) |
---|
133 | __db_err(dbenv, |
---|
134 | "__db_tas_mutex_lock: ERROR: lock currently in use: ID: %lu", |
---|
135 | (u_long)mutexp->locked); |
---|
136 | #endif |
---|
137 | #if defined(DIAGNOSTIC) || defined(HAVE_MUTEX_HPPA_MSEM_INIT) |
---|
138 | __os_id(&mutexp->locked); |
---|
139 | #endif |
---|
140 | if (ms == 1) |
---|
141 | ++mutexp->mutex_set_nowait; |
---|
142 | else |
---|
143 | ++mutexp->mutex_set_wait; |
---|
144 | return (0); |
---|
145 | } |
---|
146 | |
---|
147 | /* Yield the processor; wait 1ms initially, up to 1 second. */ |
---|
148 | __os_yield(NULL, ms * USEC_PER_MS); |
---|
149 | if ((ms <<= 1) > MS_PER_SEC) |
---|
150 | ms = MS_PER_SEC; |
---|
151 | |
---|
152 | goto loop; |
---|
153 | } |
---|
154 | |
---|
155 | /* |
---|
156 | * __db_tas_mutex_unlock -- |
---|
157 | * Release a lock. |
---|
158 | * |
---|
159 | * PUBLIC: int __db_tas_mutex_unlock __P((DB_ENV *, DB_MUTEX *)); |
---|
160 | */ |
---|
161 | int |
---|
162 | __db_tas_mutex_unlock(dbenv, mutexp) |
---|
163 | DB_ENV *dbenv; |
---|
164 | DB_MUTEX *mutexp; |
---|
165 | { |
---|
166 | if (F_ISSET(dbenv, DB_ENV_NOLOCKING) || F_ISSET(mutexp, MUTEX_IGNORE)) |
---|
167 | return (0); |
---|
168 | |
---|
169 | #ifdef DIAGNOSTIC |
---|
170 | if (!mutexp->locked) |
---|
171 | __db_err(dbenv, |
---|
172 | "__db_tas_mutex_unlock: ERROR: lock already unlocked"); |
---|
173 | #endif |
---|
174 | #if defined(DIAGNOSTIC) || defined(HAVE_MUTEX_HPPA_MSEM_INIT) |
---|
175 | mutexp->locked = 0; |
---|
176 | #endif |
---|
177 | |
---|
178 | MUTEX_UNSET(&mutexp->tas); |
---|
179 | |
---|
180 | return (0); |
---|
181 | } |
---|
182 | |
---|
183 | /* |
---|
184 | * __db_tas_mutex_destroy -- |
---|
185 | * Destroy a DB_MUTEX. |
---|
186 | * |
---|
187 | * PUBLIC: int __db_tas_mutex_destroy __P((DB_MUTEX *)); |
---|
188 | */ |
---|
189 | int |
---|
190 | __db_tas_mutex_destroy(mutexp) |
---|
191 | DB_MUTEX *mutexp; |
---|
192 | { |
---|
193 | if (F_ISSET(mutexp, MUTEX_IGNORE)) |
---|
194 | return (0); |
---|
195 | |
---|
196 | MUTEX_DESTROY(&mutexp->tas); |
---|
197 | |
---|
198 | return (0); |
---|
199 | } |
---|