Main Page | Class Hierarchy | Data Structures | Directories | File List | Data Fields | Related Pages

mut_region.c

00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 1996-2004
00005  *      Sleepycat Software.  All rights reserved.
00006  *
00007  * $Id: mut_region.c,v 12.9 2005/10/27 15:16:13 bostic Exp $
00008  */
00009 
00010 #include "db_config.h"
00011 
00012 #ifndef NO_SYSTEM_INCLUDES
00013 #include <sys/types.h>
00014 
00015 #include <string.h>
00016 #endif
00017 
00018 #include "db_int.h"
00019 #include "dbinc/db_shash.h"
00020 #include "dbinc/log.h"
00021 #include "dbinc/lock.h"
00022 #include "dbinc/mp.h"
00023 #include "dbinc/mutex_int.h"
00024 
00025 static int __mutex_region_init __P((DB_ENV *, DB_MUTEXMGR *));
00026 static size_t __mutex_region_size __P((DB_ENV *));
00027 
00028 /*
00029  * __mutex_open --
00030  *      Open a mutex region.
00031  *
00032  * PUBLIC: int __mutex_open __P((DB_ENV *));
00033  */
00034 int
00035 __mutex_open(dbenv)
00036         DB_ENV *dbenv;
00037 {
00038         DB_MUTEXMGR *mtxmgr;
00039         DB_MUTEXREGION *mtxregion;
00040         db_mutex_t mutex;
00041         u_int i;
00042         int ret;
00043 
00044         /*
00045          * Initialize the DB_ENV handle information if not already initialized.
00046          *
00047          * Align mutexes on the byte boundaries specified by the application.
00048          */
00049         if (dbenv->mutex_align == 0)
00050                 dbenv->mutex_align = MUTEX_ALIGN;
00051         if (dbenv->mutex_tas_spins == 0)
00052                 dbenv->mutex_tas_spins = __os_spin(dbenv);
00053 
00054         /*
00055          * If the user didn't set an absolute value on the number of mutexes
00056          * we'll need, figure it out.  We're conservative in our allocation,
00057          * we need mutexes for DB handles, group-commit queues and other things
00058          * applications allocate at run-time.  The application may have kicked
00059          * up our count to allocate its own mutexes, add that in.
00060          */
00061         if (dbenv->mutex_cnt == 0)
00062                 dbenv->mutex_cnt =
00063                     __lock_region_mutex_count(dbenv) +
00064                     __log_region_mutex_count(dbenv) +
00065                     __memp_region_mutex_count(dbenv) +
00066                     dbenv->mutex_inc + 500;
00067 
00068         /* Create/initialize the mutex manager structure. */
00069         if ((ret = __os_calloc(dbenv, 1, sizeof(DB_MUTEXMGR), &mtxmgr)) != 0)
00070                 return (ret);
00071 
00072         /* Join/create the txn region. */
00073         mtxmgr->reginfo.dbenv = dbenv;
00074         mtxmgr->reginfo.type = REGION_TYPE_MUTEX;
00075         mtxmgr->reginfo.id = INVALID_REGION_ID;
00076         mtxmgr->reginfo.flags = REGION_JOIN_OK;
00077         if (F_ISSET(dbenv, DB_ENV_CREATE))
00078                 F_SET(&mtxmgr->reginfo, REGION_CREATE_OK);
00079         if ((ret = __db_r_attach(dbenv,
00080             &mtxmgr->reginfo, __mutex_region_size(dbenv))) != 0)
00081                 goto err;
00082 
00083         /* If we created the region, initialize it. */
00084         if (F_ISSET(&mtxmgr->reginfo, REGION_CREATE))
00085                 if ((ret = __mutex_region_init(dbenv, mtxmgr)) != 0)
00086                         goto err;
00087 
00088         /* Set the local addresses. */
00089         mtxregion = mtxmgr->reginfo.primary =
00090             R_ADDR(&mtxmgr->reginfo, mtxmgr->reginfo.rp->primary);
00091         mtxmgr->mutex_array = R_ADDR(&mtxmgr->reginfo, mtxregion->mutex_offset);
00092 
00093         dbenv->mutex_handle = mtxmgr;
00094 
00095         /* Allocate initial queue of mutexes. */
00096         if (dbenv->mutex_iq != NULL) {
00097                 DB_ASSERT(F_ISSET(&mtxmgr->reginfo, REGION_CREATE));
00098                 for (i = 0; i < dbenv->mutex_iq_next; ++i) {
00099                         if ((ret = __mutex_alloc_int(
00100                             dbenv, 0, dbenv->mutex_iq[i].alloc_id,
00101                             dbenv->mutex_iq[i].flags, &mutex)) != 0)
00102                                 goto err;
00103                         /*
00104                          * Confirm we allocated the right index, correcting
00105                          * for avoiding slot 0 (MUTEX_INVALID).
00106                          */
00107                         DB_ASSERT(mutex == i + 1);
00108                 }
00109                 __os_free(dbenv, dbenv->mutex_iq);
00110                 dbenv->mutex_iq = NULL;
00111 
00112                 /*
00113                  * This is the first place we can test mutexes and we need to
00114                  * know if they're working.  (They CAN fail, for example on
00115                  * SunOS, when using fcntl(2) for locking and using an
00116                  * in-memory filesystem as the database environment directory.
00117                  * But you knew that, I'm sure -- it probably wasn't worth
00118                  * mentioning.)
00119                  */
00120                 mutex = MUTEX_INVALID;
00121                 if ((ret =
00122                     __mutex_alloc(dbenv, MTX_MUTEX_TEST, 0, &mutex) != 0) ||
00123                     (ret = __mutex_lock(dbenv, mutex)) != 0 ||
00124                     (ret = __mutex_unlock(dbenv, mutex)) != 0 ||
00125                     (ret = __mutex_free(dbenv, &mutex)) != 0) {
00126                         __db_err(dbenv,
00127                     "Unable to acquire/release a mutex; check configuration");
00128                         goto err;
00129                 }
00130         }
00131 
00132         /*
00133          * Initialize thread tracking.  We want to do this as early
00134          * has possible in case we die.  This sits in the mutex region
00135          * so do it now.
00136          */
00137         if ((ret = __env_thread_init(dbenv,
00138             F_ISSET(&mtxmgr->reginfo, REGION_CREATE))) != 0)
00139                 goto err;
00140 
00141         return (0);
00142 
00143 err:    dbenv->mutex_handle = NULL;
00144         if (mtxmgr->reginfo.addr != NULL)
00145                 (void)__db_r_detach(dbenv, &mtxmgr->reginfo, 0);
00146 
00147         __os_free(dbenv, mtxmgr);
00148         return (ret);
00149 }
00150 
00151 /*
00152  * __mutex_region_init --
00153  *      Initialize a mutex region in shared memory.
00154  */
00155 static int
00156 __mutex_region_init(dbenv, mtxmgr)
00157         DB_ENV *dbenv;
00158         DB_MUTEXMGR *mtxmgr;
00159 {
00160         DB_MUTEXREGION *mtxregion;
00161         DB_MUTEX *mutexp;
00162         db_mutex_t i;
00163         int ret;
00164         void *mutex_array;
00165 
00166         COMPQUIET(mutexp, NULL);
00167 
00168         if ((ret = __db_shalloc(&mtxmgr->reginfo,
00169             sizeof(DB_MUTEXREGION), 0, &mtxmgr->reginfo.primary)) != 0) {
00170                 __db_err(dbenv,
00171                     "Unable to allocate memory for the mutex region");
00172                 return (ret);
00173         }
00174         mtxmgr->reginfo.rp->primary =
00175             R_OFFSET(&mtxmgr->reginfo, mtxmgr->reginfo.primary);
00176         mtxregion = mtxmgr->reginfo.primary;
00177         memset(mtxregion, 0, sizeof(*mtxregion));
00178 
00179         if ((ret = __mutex_alloc(
00180             dbenv, MTX_MUTEX_REGION, 0, &mtxregion->mtx_region)) != 0)
00181                 return (ret);
00182 
00183         mtxregion->mutex_size =
00184             (size_t)DB_ALIGN(sizeof(DB_MUTEX), dbenv->mutex_align);
00185 
00186         mtxregion->stat.st_mutex_align = dbenv->mutex_align;
00187         mtxregion->stat.st_mutex_cnt = dbenv->mutex_cnt;
00188         mtxregion->stat.st_mutex_tas_spins = dbenv->mutex_tas_spins;
00189 
00190         /*
00191          * Get a chunk of memory to be used for the mutexes themselves.  Each
00192          * piece of the memory must be properly aligned.
00193          *
00194          * The OOB mutex (MUTEX_INVALID) is 0.  To make this work, we ignore
00195          * the first allocated slot when we build the free list.  We have to
00196          * correct the count by 1 here, though, otherwise our counter will be
00197          * off by 1.
00198          */
00199         if ((ret = __db_shalloc(&mtxmgr->reginfo,
00200             (mtxregion->stat.st_mutex_cnt + 1) * mtxregion->mutex_size,
00201             mtxregion->stat.st_mutex_align, &mutex_array)) != 0) {
00202                 __db_err(dbenv,
00203                     "Unable to allocate memory for mutexes from the region");
00204                 return (ret);
00205         }
00206 
00207         mtxregion->mutex_offset = R_OFFSET(&mtxmgr->reginfo, mutex_array);
00208         mtxmgr->mutex_array = mutex_array;
00209 
00210         /*
00211          * Put the mutexes on a free list and clear the allocated flag.
00212          *
00213          * The OOB mutex (MUTEX_INVALID) is 0, skip it.
00214          *
00215          * The comparison is <, not <=, because we're looking ahead one
00216          * in each link.
00217          */
00218         for (i = 1; i < mtxregion->stat.st_mutex_cnt; ++i) {
00219                 mutexp = MUTEXP_SET(i);
00220                 mutexp->flags = 0;
00221                 mutexp->mutex_next_link = i + 1;
00222         }
00223         mutexp = MUTEXP_SET(i);
00224         mutexp->flags = 0;
00225         mutexp->mutex_next_link = MUTEX_INVALID;
00226         mtxregion->mutex_next = 1;
00227         mtxregion->stat.st_mutex_free = mtxregion->stat.st_mutex_cnt;
00228         mtxregion->stat.st_mutex_inuse = mtxregion->stat.st_mutex_inuse_max = 0;
00229 
00230         return (0);
00231 }
00232 
00233 /*
00234  * __mutex_dbenv_refresh --
00235  *      Clean up after the mutex region on a close or failed open.
00236  *
00237  * PUBLIC: int __mutex_dbenv_refresh __P((DB_ENV *));
00238  */
00239 int
00240 __mutex_dbenv_refresh(dbenv)
00241         DB_ENV *dbenv;
00242 {
00243         DB_MUTEXMGR *mtxmgr;
00244         DB_MUTEXREGION *mtxregion;
00245         REGINFO *reginfo;
00246         int ret;
00247 
00248         mtxmgr = dbenv->mutex_handle;
00249         reginfo = &mtxmgr->reginfo;
00250         mtxregion = mtxmgr->reginfo.primary;
00251 
00252         /*
00253          * If a private region, return the memory to the heap.  Not needed for
00254          * filesystem-backed or system shared memory regions, that memory isn't
00255          * owned by any particular process.
00256          */
00257         if (F_ISSET(dbenv, DB_ENV_PRIVATE)) {
00258 #ifdef HAVE_MUTEX_SYSTEM_RESOURCES
00259                 /*
00260                  * If destroying the mutex region, return any system resources
00261                  * to the system.
00262                  */
00263                 __mutex_resource_return(dbenv, reginfo);
00264 #endif
00265                 /* Discard the mutex array. */
00266                 __db_shalloc_free(
00267                     reginfo, R_ADDR(reginfo, mtxregion->mutex_offset));
00268         }
00269 
00270         /* Detach from the region. */
00271         ret = __db_r_detach(dbenv, reginfo, 0);
00272 
00273         __os_free(dbenv, mtxmgr);
00274 
00275         dbenv->mutex_handle = NULL;
00276 
00277         return (ret);
00278 }
00279 
00280 /*
00281  * __mutex_region_size --
00282  *       Return the amount of space needed for the mutex region.
00283  */
00284 static size_t
00285 __mutex_region_size(dbenv)
00286         DB_ENV *dbenv;
00287 {
00288         size_t s;
00289 
00290         s = sizeof(DB_MUTEXMGR) + 1024;
00291         s += dbenv->mutex_cnt *
00292             __db_shalloc_size(sizeof(DB_MUTEX), dbenv->mutex_align);
00293         /*
00294          * Allocate space for thread info blocks.  Max is only advisory,
00295          * so we allocate 25% more.
00296          */
00297         s += (dbenv->thr_max + dbenv->thr_max/4) *
00298             __db_shalloc_size(sizeof(DB_THREAD_INFO), sizeof(roff_t));
00299         s += dbenv->thr_nbucket *
00300             __db_shalloc_size(sizeof(DB_HASHTAB), sizeof(roff_t));
00301         return (s);
00302 }
00303 
00304 #ifdef  HAVE_MUTEX_SYSTEM_RESOURCES
00305 /*
00306  * __mutex_resource_return
00307  *      Return any system-allocated mutex resources to the system.
00308  *
00309  * PUBLIC: void __mutex_resource_return __P((DB_ENV *, REGINFO *));
00310  */
00311 void
00312 __mutex_resource_return(dbenv, infop)
00313         DB_ENV *dbenv;
00314         REGINFO *infop;
00315 {
00316         DB_MUTEX *mutexp;
00317         DB_MUTEXMGR *mtxmgr, mtxmgr_st;
00318         DB_MUTEXREGION *mtxregion;
00319         db_mutex_t i;
00320         void *orig_handle;
00321 
00322         /*
00323          * This routine is called in two cases: when discarding the regions
00324          * from a previous Berkeley DB run, during recovery, and two, when
00325          * discarding regions as we shut down the database environment.
00326          *
00327          * Walk the list of mutexes and destroy any live ones.
00328          *
00329          * This is just like joining a region -- the REGINFO we're handed
00330          * is the same as the one returned by __db_r_attach(), all we have
00331          * to do is fill in the links.
00332          *
00333          * !!!
00334          * The region may be corrupted, of course.  We're safe because the
00335          * only things we look at are things that are initialized when the
00336          * region is created, and never modified after that.
00337          */
00338         memset(&mtxmgr_st, 0, sizeof(mtxmgr_st));
00339         mtxmgr = &mtxmgr_st;
00340         mtxmgr->reginfo = *infop;
00341         mtxregion = mtxmgr->reginfo.primary =
00342             R_ADDR(&mtxmgr->reginfo, mtxmgr->reginfo.rp->primary);
00343         mtxmgr->mutex_array = R_ADDR(&mtxmgr->reginfo, mtxregion->mutex_offset);
00344 
00345         /*
00346          * This is a little strange, but the mutex_handle is what all of the
00347          * underlying mutex routines will use to determine if they should do
00348          * any work and to find their information.  Save/restore the handle
00349          * around the work loop.
00350          *
00351          * The OOB mutex (MUTEX_INVALID) is 0, skip it.
00352          */
00353         orig_handle = dbenv->mutex_handle;
00354         dbenv->mutex_handle = mtxmgr;
00355         for (i = 1; i <= mtxregion->stat.st_mutex_cnt; ++i, ++mutexp) {
00356                 mutexp = MUTEXP_SET(i);
00357                 if (F_ISSET(mutexp, DB_MUTEX_ALLOCATED))
00358                         (void)__mutex_destroy(dbenv, i);
00359         }
00360         dbenv->mutex_handle = orig_handle;
00361 }
00362 #endif

Generated on Sun Dec 25 12:14:41 2005 for Berkeley DB 4.4.16 by  doxygen 1.4.2