2 * See the file LICENSE for redistribution information.
4 * Copyright (c) 1996-2009 Oracle. All rights reserved.
12 #include "dbinc/log.h"
13 #include "dbinc/lock.h"
15 #include "dbinc/txn.h"
17 static size_t __mutex_align_size __P((ENV *));
18 static int __mutex_region_init __P((ENV *, DB_MUTEXMGR *));
19 static size_t __mutex_region_size __P((ENV *));
23 * Open a mutex region.
25 * PUBLIC: int __mutex_open __P((ENV *, int));
28 __mutex_open(env, create_ok)
34 DB_MUTEXREGION *mtxregion;
43 * Initialize the ENV handle information if not already initialized.
45 * Align mutexes on the byte boundaries specified by the application.
47 if (dbenv->mutex_align == 0)
48 dbenv->mutex_align = MUTEX_ALIGN;
49 if (dbenv->mutex_tas_spins == 0) {
50 cpu_count = __os_cpu_count();
51 if ((ret = __mutex_set_tas_spins(dbenv, cpu_count == 1 ?
52 cpu_count : cpu_count * MUTEX_SPINS_PER_PROCESSOR)) != 0)
57 * If the user didn't set an absolute value on the number of mutexes
58 * we'll need, figure it out. We're conservative in our allocation,
59 * we need mutexes for DB handles, group-commit queues and other things
60 * applications allocate at run-time. The application may have kicked
61 * up our count to allocate its own mutexes, add that in.
63 if (dbenv->mutex_cnt == 0)
65 __lock_region_mutex_count(env) +
66 __log_region_mutex_count(env) +
67 __memp_region_mutex_count(env) +
68 __txn_region_mutex_count(env) +
69 dbenv->mutex_inc + 100;
71 /* Create/initialize the mutex manager structure. */
72 if ((ret = __os_calloc(env, 1, sizeof(DB_MUTEXMGR), &mtxmgr)) != 0)
75 /* Join/create the mutex region. */
76 mtxmgr->reginfo.env = env;
77 mtxmgr->reginfo.type = REGION_TYPE_MUTEX;
78 mtxmgr->reginfo.id = INVALID_REGION_ID;
79 mtxmgr->reginfo.flags = REGION_JOIN_OK;
81 F_SET(&mtxmgr->reginfo, REGION_CREATE_OK);
82 if ((ret = __env_region_attach(env,
83 &mtxmgr->reginfo, __mutex_region_size(env))) != 0)
86 /* If we created the region, initialize it. */
87 if (F_ISSET(&mtxmgr->reginfo, REGION_CREATE))
88 if ((ret = __mutex_region_init(env, mtxmgr)) != 0)
91 /* Set the local addresses. */
92 mtxregion = mtxmgr->reginfo.primary =
93 R_ADDR(&mtxmgr->reginfo, mtxmgr->reginfo.rp->primary);
94 mtxmgr->mutex_array = R_ADDR(&mtxmgr->reginfo, mtxregion->mutex_off);
96 env->mutex_handle = mtxmgr;
98 /* Allocate initial queue of mutexes. */
99 if (env->mutex_iq != NULL) {
100 DB_ASSERT(env, F_ISSET(&mtxmgr->reginfo, REGION_CREATE));
101 for (i = 0; i < env->mutex_iq_next; ++i) {
102 if ((ret = __mutex_alloc_int(
103 env, 0, env->mutex_iq[i].alloc_id,
104 env->mutex_iq[i].flags, &mutex)) != 0)
107 * Confirm we allocated the right index, correcting
108 * for avoiding slot 0 (MUTEX_INVALID).
110 DB_ASSERT(env, mutex == i + 1);
112 __os_free(env, env->mutex_iq);
113 env->mutex_iq = NULL;
114 #ifndef HAVE_ATOMIC_SUPPORT
115 /* If necessary allocate the atomic emulation mutexes. */
116 for (i = 0; i != MAX_ATOMIC_MUTEXES; i++)
117 if ((ret = __mutex_alloc_int(
118 env, 0, MTX_ATOMIC_EMULATION,
119 0, &mtxregion->mtx_atomic[i])) != 0)
124 * This is the first place we can test mutexes and we need to
125 * know if they're working. (They CAN fail, for example on
126 * SunOS, when using fcntl(2) for locking and using an
127 * in-memory filesystem as the database environment directory.
128 * But you knew that, I'm sure -- it probably wasn't worth
131 mutex = MUTEX_INVALID;
133 __mutex_alloc(env, MTX_MUTEX_TEST, 0, &mutex) != 0) ||
134 (ret = __mutex_lock(env, mutex)) != 0 ||
135 (ret = __mutex_unlock(env, mutex)) != 0 ||
136 (ret = __mutex_trylock(env, mutex)) != 0 ||
137 (ret = __mutex_unlock(env, mutex)) != 0 ||
138 (ret = __mutex_free(env, &mutex)) != 0) {
140 "Unable to acquire/release a mutex; check configuration");
143 #ifdef HAVE_SHARED_LATCHES
146 MTX_MUTEX_TEST, DB_MUTEX_SHARED, &mutex) != 0) ||
147 (ret = __mutex_lock(env, mutex)) != 0 ||
148 (ret = __mutex_unlock(env, mutex)) != 0 ||
149 (ret = __mutex_rdlock(env, mutex)) != 0 ||
150 (ret = __mutex_rdlock(env, mutex)) != 0 ||
151 (ret = __mutex_unlock(env, mutex)) != 0 ||
152 (ret = __mutex_unlock(env, mutex)) != 0 ||
153 (ret = __mutex_free(env, &mutex)) != 0) {
155 "Unable to acquire/release a shared latch; check configuration");
162 err: env->mutex_handle = NULL;
163 if (mtxmgr->reginfo.addr != NULL)
164 (void)__env_region_detach(env, &mtxmgr->reginfo, 0);
166 __os_free(env, mtxmgr);
171 * __mutex_region_init --
172 * Initialize a mutex region in shared memory.
175 __mutex_region_init(env, mtxmgr)
181 DB_MUTEXREGION *mtxregion;
188 COMPQUIET(mutexp, NULL);
190 if ((ret = __env_alloc(&mtxmgr->reginfo,
191 sizeof(DB_MUTEXREGION), &mtxmgr->reginfo.primary)) != 0) {
193 "Unable to allocate memory for the mutex region");
196 mtxmgr->reginfo.rp->primary =
197 R_OFFSET(&mtxmgr->reginfo, mtxmgr->reginfo.primary);
198 mtxregion = mtxmgr->reginfo.primary;
199 memset(mtxregion, 0, sizeof(*mtxregion));
201 if ((ret = __mutex_alloc(
202 env, MTX_MUTEX_REGION, 0, &mtxregion->mtx_region)) != 0)
204 mtxmgr->reginfo.mtx_alloc = mtxregion->mtx_region;
206 mtxregion->mutex_size = __mutex_align_size(env);
208 mtxregion->stat.st_mutex_align = dbenv->mutex_align;
209 mtxregion->stat.st_mutex_cnt = dbenv->mutex_cnt;
210 mtxregion->stat.st_mutex_tas_spins = dbenv->mutex_tas_spins;
213 * Get a chunk of memory to be used for the mutexes themselves. Each
214 * piece of the memory must be properly aligned, and that alignment
215 * may be more restrictive than the memory alignment returned by the
216 * underlying allocation code. We already know how much memory each
217 * mutex in the array will take up, but we need to offset the first
218 * mutex in the array so the array begins properly aligned.
220 * The OOB mutex (MUTEX_INVALID) is 0. To make this work, we ignore
221 * the first allocated slot when we build the free list. We have to
222 * correct the count by 1 here, though, otherwise our counter will be
225 if ((ret = __env_alloc(&mtxmgr->reginfo,
226 mtxregion->stat.st_mutex_align +
227 (mtxregion->stat.st_mutex_cnt + 1) * mtxregion->mutex_size,
228 &mutex_array)) != 0) {
230 "Unable to allocate memory for mutexes from the region");
234 mtxregion->mutex_off_alloc = R_OFFSET(&mtxmgr->reginfo, mutex_array);
235 mutex_array = ALIGNP_INC(mutex_array, mtxregion->stat.st_mutex_align);
236 mtxregion->mutex_off = R_OFFSET(&mtxmgr->reginfo, mutex_array);
237 mtxmgr->mutex_array = mutex_array;
240 * Put the mutexes on a free list and clear the allocated flag.
242 * The OOB mutex (MUTEX_INVALID) is 0, skip it.
244 * The comparison is <, not <=, because we're looking ahead one
247 for (i = 1; i < mtxregion->stat.st_mutex_cnt; ++i) {
248 mutexp = MUTEXP_SET(mtxmgr, i);
250 mutexp->mutex_next_link = i + 1;
252 mutexp = MUTEXP_SET(mtxmgr, i);
254 mutexp->mutex_next_link = MUTEX_INVALID;
255 mtxregion->mutex_next = 1;
256 mtxregion->stat.st_mutex_free = mtxregion->stat.st_mutex_cnt;
257 mtxregion->stat.st_mutex_inuse = mtxregion->stat.st_mutex_inuse_max = 0;
263 * __mutex_env_refresh --
264 * Clean up after the mutex region on a close or failed open.
266 * PUBLIC: int __mutex_env_refresh __P((ENV *));
269 __mutex_env_refresh(env)
273 DB_MUTEXREGION *mtxregion;
277 mtxmgr = env->mutex_handle;
278 reginfo = &mtxmgr->reginfo;
279 mtxregion = mtxmgr->reginfo.primary;
282 * If a private region, return the memory to the heap. Not needed for
283 * filesystem-backed or system shared memory regions, that memory isn't
284 * owned by any particular process.
286 if (F_ISSET(env, ENV_PRIVATE)) {
287 reginfo->mtx_alloc = MUTEX_INVALID;
289 #ifdef HAVE_MUTEX_SYSTEM_RESOURCES
291 * If destroying the mutex region, return any system resources
294 __mutex_resource_return(env, reginfo);
296 /* Discard the mutex array. */
298 reginfo, R_ADDR(reginfo, mtxregion->mutex_off_alloc));
301 /* Detach from the region. */
302 ret = __env_region_detach(env, reginfo, 0);
304 __os_free(env, mtxmgr);
306 env->mutex_handle = NULL;
312 * __mutex_align_size --
313 * Return how much memory each mutex will take up if an array of them
314 * are to be properly aligned, individually, within the array.
317 __mutex_align_size(env)
324 return ((size_t)DB_ALIGN(sizeof(DB_MUTEX), dbenv->mutex_align));
328 * __mutex_region_size --
329 * Return the amount of space needed for the mutex region.
332 __mutex_region_size(env)
340 s = sizeof(DB_MUTEXMGR) + 1024;
342 /* We discard one mutex for the OOB slot. */
343 s += __env_alloc_size(
344 (dbenv->mutex_cnt + 1) *__mutex_align_size(env));
349 #ifdef HAVE_MUTEX_SYSTEM_RESOURCES
351 * __mutex_resource_return
352 * Return any system-allocated mutex resources to the system.
354 * PUBLIC: void __mutex_resource_return __P((ENV *, REGINFO *));
357 __mutex_resource_return(env, infop)
362 DB_MUTEXMGR *mtxmgr, mtxmgr_st;
363 DB_MUTEXREGION *mtxregion;
368 * This routine is called in two cases: when discarding the regions
369 * from a previous Berkeley DB run, during recovery, and two, when
370 * discarding regions as we shut down the database environment.
372 * Walk the list of mutexes and destroy any live ones.
374 * This is just like joining a region -- the REGINFO we're handed is
375 * the same as the one returned by __env_region_attach(), all we have
376 * to do is fill in the links.
379 * The region may be corrupted, of course. We're safe because the
380 * only things we look at are things that are initialized when the
381 * region is created, and never modified after that.
383 memset(&mtxmgr_st, 0, sizeof(mtxmgr_st));
385 mtxmgr->reginfo = *infop;
386 mtxregion = mtxmgr->reginfo.primary =
387 R_ADDR(&mtxmgr->reginfo, mtxmgr->reginfo.rp->primary);
388 mtxmgr->mutex_array = R_ADDR(&mtxmgr->reginfo, mtxregion->mutex_off);
391 * This is a little strange, but the mutex_handle is what all of the
392 * underlying mutex routines will use to determine if they should do
393 * any work and to find their information. Save/restore the handle
394 * around the work loop.
396 * The OOB mutex (MUTEX_INVALID) is 0, skip it.
398 orig_handle = env->mutex_handle;
399 env->mutex_handle = mtxmgr;
400 for (i = 1; i <= mtxregion->stat.st_mutex_cnt; ++i, ++mutexp) {
401 mutexp = MUTEXP_SET(mtxmgr, i);
402 if (F_ISSET(mutexp, DB_MUTEX_ALLOCATED))
403 (void)__mutex_destroy(env, i);
405 env->mutex_handle = orig_handle;