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

mut_alloc.c

00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 1999-2005
00005  *      Sleepycat Software.  All rights reserved.
00006  *
00007  * $Id: mut_alloc.c,v 12.6 2005/08/08 14:57:54 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/mutex_int.h"
00020 
00021 static int __mutex_free_int __P((DB_ENV *, int, db_mutex_t *));
00022 
00023 /*
00024  * __mutex_alloc --
00025  *      Allocate a mutex from the mutex region.
00026  *
00027  * PUBLIC: int __mutex_alloc __P((DB_ENV *, int, u_int32_t, db_mutex_t *));
00028  */
00029 int
00030 __mutex_alloc(dbenv, alloc_id, flags, indxp)
00031         DB_ENV *dbenv;
00032         int alloc_id;
00033         u_int32_t flags;
00034         db_mutex_t *indxp;
00035 {
00036         int ret;
00037 
00038         /* The caller may depend on us to initialize. */
00039         *indxp = MUTEX_INVALID;
00040 
00041         /*
00042          * If this is not an application lock, and we've turned off locking,
00043          * or the DB_ENV handle isn't thread-safe, and this is a thread lock
00044          * or the environment isn't multi-process by definition, there's no
00045          * need to mutex at all.
00046          */
00047         if (alloc_id != MTX_APPLICATION &&
00048             (F_ISSET(dbenv, DB_ENV_NOLOCKING) ||
00049             (!F_ISSET(dbenv, DB_ENV_THREAD) &&
00050             (LF_ISSET(DB_MUTEX_THREAD) || F_ISSET(dbenv, DB_ENV_PRIVATE)))))
00051                 return (0);
00052 
00053         /*
00054          * If we have a region in which to allocate the mutexes, lock it and
00055          * do the allocation.
00056          */
00057         if (MUTEX_ON(dbenv))
00058                 return (__mutex_alloc_int(dbenv, 1, alloc_id, flags, indxp));
00059 
00060         /*
00061          * We have to allocate some number of mutexes before we have a region
00062          * in which to allocate them.  We handle this by saving up the list of
00063          * flags and allocating them as soon as we have a handle.
00064          *
00065          * The list of mutexes to alloc is maintained in pairs: first the
00066          * alloc_id argument, second the flags passed in by the caller.
00067          */
00068         if (dbenv->mutex_iq == NULL) {
00069                 dbenv->mutex_iq_max = 50;
00070                 if ((ret = __os_calloc(dbenv, dbenv->mutex_iq_max,
00071                     sizeof(dbenv->mutex_iq[0]), &dbenv->mutex_iq)) != 0)
00072                         return (ret);
00073         } else if (dbenv->mutex_iq_next == dbenv->mutex_iq_max - 1) {
00074                 dbenv->mutex_iq_max *= 2;
00075                 if ((ret = __os_realloc(dbenv,
00076                     dbenv->mutex_iq_max * sizeof(dbenv->mutex_iq[0]),
00077                     &dbenv->mutex_iq)) != 0)
00078                         return (ret);
00079         }
00080         *indxp = dbenv->mutex_iq_next + 1;      /* Correct for MUTEX_INVALID. */
00081         dbenv->mutex_iq[dbenv->mutex_iq_next].alloc_id = alloc_id;
00082         dbenv->mutex_iq[dbenv->mutex_iq_next].flags = flags;
00083         ++dbenv->mutex_iq_next;
00084 
00085         return (0);
00086 }
00087 
00088 /*
00089  * __mutex_alloc_int --
00090  *      Internal routine to allocate a mutex.
00091  *
00092  * PUBLIC: int __mutex_alloc_int
00093  * PUBLIC:      __P((DB_ENV *, int, int, u_int32_t, db_mutex_t *));
00094  */
00095 int
00096 __mutex_alloc_int(dbenv, locksys, alloc_id, flags, indxp)
00097         DB_ENV *dbenv;
00098         int locksys, alloc_id;
00099         u_int32_t flags;
00100         db_mutex_t *indxp;
00101 {
00102         DB_MUTEX *mutexp;
00103         DB_MUTEXMGR *mtxmgr;
00104         DB_MUTEXREGION *mtxregion;
00105         int ret;
00106 
00107         mtxmgr = dbenv->mutex_handle;
00108         mtxregion = mtxmgr->reginfo.primary;
00109         ret = 0;
00110 
00111         /*
00112          * If we're not initializing the mutex region, then lock the region to
00113          * allocate new mutexes.  Drop the lock before initializing the mutex,
00114          * mutex initialization may require a system call.
00115          */
00116         if (locksys)
00117                 MUTEX_SYSTEM_LOCK(dbenv);
00118 
00119         if (mtxregion->mutex_next == MUTEX_INVALID) {
00120                 __db_err(dbenv,
00121                     "unable to allocate memory for mutex; resize mutex region");
00122                 if (locksys)
00123                         MUTEX_SYSTEM_UNLOCK(dbenv);
00124                 return (ENOMEM);
00125         }
00126 
00127         *indxp = mtxregion->mutex_next;
00128         mutexp = MUTEXP_SET(*indxp);
00129         mtxregion->mutex_next = mutexp->mutex_next_link;
00130 
00131         --mtxregion->stat.st_mutex_free;
00132         ++mtxregion->stat.st_mutex_inuse;
00133         if (mtxregion->stat.st_mutex_inuse > mtxregion->stat.st_mutex_inuse_max)
00134                 mtxregion->stat.st_mutex_inuse_max =
00135                     mtxregion->stat.st_mutex_inuse;
00136         if (locksys)
00137                 MUTEX_SYSTEM_UNLOCK(dbenv);
00138 
00139         /* Initialize the mutex. */
00140         memset(mutexp, 0, sizeof(*mutexp));
00141 
00142         F_SET(mutexp, DB_MUTEX_ALLOCATED);
00143         if (LF_ISSET(DB_MUTEX_LOGICAL_LOCK))
00144                 F_SET(mutexp, DB_MUTEX_LOGICAL_LOCK);
00145 
00146 #ifdef DIAGNOSTIC
00147         mutexp->alloc_id = alloc_id;
00148 #else
00149         COMPQUIET(alloc_id, 0);
00150 #endif
00151 
00152         if ((ret = __mutex_init(dbenv, *indxp, flags)) != 0)
00153                 (void)__mutex_free_int(dbenv, locksys, indxp);
00154 
00155         return (ret);
00156 }
00157 
00158 /*
00159  * __mutex_free --
00160  *      Free a mutex.
00161  *
00162  * PUBLIC: int __mutex_free __P((DB_ENV *, db_mutex_t *));
00163  */
00164 int
00165 __mutex_free(dbenv, indxp)
00166         DB_ENV *dbenv;
00167         db_mutex_t *indxp;
00168 {
00169         /*
00170          * There is no explicit ordering in how the regions are cleaned up
00171          * up and/or discarded when an environment is destroyed (either a
00172          * private environment is closed or a public environment is removed).
00173          * The way we deal with mutexes is to clean up all remaining mutexes
00174          * when we close the mutex environment (because we have to be able to
00175          * do that anyway, after a crash), which means we don't have to deal
00176          * with region cleanup ordering on normal environment destruction.
00177          * All that said, what it really means is we can get here without a
00178          * mpool region.  It's OK, the mutex has been, or will be, destroyed.
00179          *
00180          * If the mutex has never been configured, we're done.
00181          */
00182         if (!MUTEX_ON(dbenv) || *indxp == MUTEX_INVALID)
00183                 return (0);
00184 
00185         return (__mutex_free_int(dbenv, 1, indxp));
00186 }
00187 
00188 /*
00189  * __mutex_free_int --
00190  *      Internal routine to free a mutex.
00191  */
00192 static int
00193 __mutex_free_int(dbenv, locksys, indxp)
00194         DB_ENV *dbenv;
00195         int locksys;
00196         db_mutex_t *indxp;
00197 {
00198         DB_MUTEX *mutexp;
00199         DB_MUTEXMGR *mtxmgr;
00200         DB_MUTEXREGION *mtxregion;
00201         db_mutex_t mutex;
00202         int ret;
00203 
00204         mutex = *indxp;
00205         *indxp = MUTEX_INVALID;
00206 
00207         mtxmgr = dbenv->mutex_handle;
00208         mtxregion = mtxmgr->reginfo.primary;
00209         mutexp = MUTEXP_SET(mutex);
00210 
00211         DB_ASSERT(F_ISSET(mutexp, DB_MUTEX_ALLOCATED));
00212         F_CLR(mutexp, DB_MUTEX_ALLOCATED);
00213 
00214         ret = __mutex_destroy(dbenv, mutex);
00215 
00216         if (locksys)
00217                 MUTEX_SYSTEM_LOCK(dbenv);
00218 
00219         /* Link the mutex on the head of the free list. */
00220         mutexp->mutex_next_link = mtxregion->mutex_next;
00221         mtxregion->mutex_next = mutex;
00222         ++mtxregion->stat.st_mutex_free;
00223         --mtxregion->stat.st_mutex_inuse;
00224 
00225         if (locksys)
00226                 MUTEX_SYSTEM_UNLOCK(dbenv);
00227 
00228         return (ret);
00229 }

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