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

mut_tas.c

00001 /*-
00002  * See the file LICENSE for redistribution information.
00003  *
00004  * Copyright (c) 1996-2005
00005  *      Sleepycat Software.  All rights reserved.
00006  *
00007  * $Id: mut_tas.c,v 12.14 2005/11/01 14:42:17 bostic Exp $
00008  */
00009 
00010 #include "db_config.h"
00011 
00012 #ifndef NO_SYSTEM_INCLUDES
00013 #include <sys/types.h>
00014 
00015 #include <stdlib.h>
00016 #include <string.h>
00017 #endif
00018 
00019 #include "db_int.h"
00020 
00021 /*
00022  * This is where we load in the actual test-and-set mutex code.
00023  */
00024 #define LOAD_ACTUAL_MUTEX_CODE
00025 #include "dbinc/mutex_int.h"
00026 
00027 /*
00028  * __db_tas_mutex_init --
00029  *      Initialize a test-and-set mutex.
00030  *
00031  * PUBLIC: int __db_tas_mutex_init __P((DB_ENV *, db_mutex_t, u_int32_t));
00032  */
00033 int
00034 __db_tas_mutex_init(dbenv, mutex, flags)
00035         DB_ENV *dbenv;
00036         db_mutex_t mutex;
00037         u_int32_t flags;
00038 {
00039         DB_MUTEX *mutexp;
00040         DB_MUTEXMGR *mtxmgr;
00041         DB_MUTEXREGION *mtxregion;
00042         int ret;
00043 
00044         COMPQUIET(flags, 0);
00045 
00046         mtxmgr = dbenv->mutex_handle;
00047         mtxregion = mtxmgr->reginfo.primary;
00048         mutexp = MUTEXP_SET(mutex);
00049 
00050         /* Check alignment. */
00051         if (((uintptr_t)mutexp & (dbenv->mutex_align - 1)) != 0) {
00052                 __db_err(dbenv, "TAS: mutex not appropriately aligned");
00053                 return (EINVAL);
00054         }
00055 
00056         if (MUTEX_INIT(&mutexp->tas)) {
00057                 ret = __os_get_errno();
00058                 __db_err(dbenv,
00059                     "TAS: mutex initialize: %s", db_strerror(ret));
00060                 return (ret);
00061         }
00062         return (0);
00063 }
00064 
00065 /*
00066  * __db_tas_mutex_lock
00067  *      Lock on a mutex, blocking if necessary.
00068  *
00069  * PUBLIC: int __db_tas_mutex_lock __P((DB_ENV *, db_mutex_t));
00070  */
00071 int
00072 __db_tas_mutex_lock(dbenv, mutex)
00073         DB_ENV *dbenv;
00074         db_mutex_t mutex;
00075 {
00076         DB_MUTEX *mutexp;
00077         DB_MUTEXMGR *mtxmgr;
00078         DB_MUTEXREGION *mtxregion;
00079         u_int32_t nspins;
00080         u_long ms, max_ms;
00081 
00082         if (!MUTEX_ON(dbenv) || F_ISSET(dbenv, DB_ENV_NOLOCKING))
00083                 return (0);
00084 
00085         mtxmgr = dbenv->mutex_handle;
00086         mtxregion = mtxmgr->reginfo.primary;
00087         mutexp = MUTEXP_SET(mutex);
00088 
00089 #ifdef HAVE_STATISTICS
00090         if (F_ISSET(mutexp, DB_MUTEX_LOCKED))
00091                 ++mutexp->mutex_set_wait;
00092         else
00093                 ++mutexp->mutex_set_nowait;
00094 #endif
00095 
00096         /*
00097          * Wait 1ms initially, up to 10ms for mutexes backing logical database
00098          * locks, and up to 25 ms for mutual exclusion data structure mutexes.
00099          * SR: #7675
00100          */
00101         ms = 1;
00102         max_ms = F_ISSET(mutexp, DB_MUTEX_LOGICAL_LOCK) ? 10 : 25;
00103 
00104 loop:   /* Attempt to acquire the resource for N spins. */
00105         for (nspins =
00106             mtxregion->stat.st_mutex_tas_spins; nspins > 0; --nspins) {
00107 #ifdef HAVE_MUTEX_HPPA_MSEM_INIT
00108 relock:
00109 #endif
00110 #ifdef HAVE_MUTEX_S390_CC_ASSEMBLY
00111                 tsl_t zero = 0;
00112 #endif
00113                 /*
00114                  * Avoid interlocked instructions until they're likely to
00115                  * succeed.
00116                  */
00117                 if (F_ISSET(mutexp, DB_MUTEX_LOCKED) ||
00118                     !MUTEX_SET(&mutexp->tas)) {
00119                         /*
00120                          * Some systems (notably those with newer Intel CPUs)
00121                          * need a small pause here. [#6975]
00122                          */
00123 #ifdef MUTEX_PAUSE
00124                         MUTEX_PAUSE
00125 #endif
00126                         continue;
00127                 }
00128 
00129 #ifdef HAVE_MUTEX_HPPA_MSEM_INIT
00130                 /*
00131                  * HP semaphores are unlocked automatically when a holding
00132                  * process exits.  If the mutex appears to be locked
00133                  * (F_ISSET(DB_MUTEX_LOCKED)) but we got here, assume this
00134                  * has happened.  Set the pid and tid into the mutex and
00135                  * lock again.  (The default state of the mutexes used to
00136                  * block in __lock_get_internal is locked, so exiting with
00137                  * a locked mutex is reasonable behavior for a process that
00138                  * happened to initialize or use one of them.)
00139                  */
00140                 if (F_ISSET(mutexp, DB_MUTEX_LOCKED)) {
00141                         F_SET(mutexp, DB_MUTEX_LOCKED);
00142                         dbenv->thread_id(dbenv, &mutexp->pid, &mutexp->tid);
00143                         CHECK_MTX_THREAD(dbenv, mutexp);
00144                         goto relock;
00145                 }
00146                 /*
00147                  * If we make it here, the mutex isn't locked, the diagnostic
00148                  * won't fire, and we were really unlocked by someone calling
00149                  * the DB mutex unlock function.
00150                  */
00151 #endif
00152 #ifdef DIAGNOSTIC
00153                 if (F_ISSET(mutexp, DB_MUTEX_LOCKED)) {
00154                         char buf[DB_THREADID_STRLEN];
00155                         __db_err(dbenv,
00156                               "TAS lock failed: lock currently in use: ID: %s",
00157                               dbenv->thread_id_string(dbenv,
00158                               mutexp->pid, mutexp->tid, buf));
00159                         return (__db_panic(dbenv, EACCES));
00160                 }
00161 #endif
00162                 F_SET(mutexp, DB_MUTEX_LOCKED);
00163                 dbenv->thread_id(dbenv, &mutexp->pid, &mutexp->tid);
00164                 CHECK_MTX_THREAD(dbenv, mutexp);
00165 
00166 #ifdef DIAGNOSTIC
00167                 /*
00168                  * We want to switch threads as often as possible.  Yield
00169                  * every time we get a mutex to ensure contention.
00170                  */
00171                 if (F_ISSET(dbenv, DB_ENV_YIELDCPU))
00172                         __os_yield(NULL, 1);
00173 #endif
00174                 return (0);
00175         }
00176 
00177         /*
00178          * Yield the processor.
00179          */
00180         __os_yield(NULL, ms * USEC_PER_MS);
00181         if ((ms <<= 1) > max_ms)
00182                 ms = max_ms;
00183 
00184         /*
00185          * We're spinning.  The environment might be hung, and somebody else
00186          * has already recovered it.  The first thing recovery does is panic
00187          * the environment.  Check to see if we're never going to get this
00188          * mutex.
00189          */
00190         PANIC_CHECK(dbenv);
00191 
00192         goto loop;
00193 }
00194 
00195 /*
00196  * __db_tas_mutex_unlock --
00197  *      Release a mutex.
00198  *
00199  * PUBLIC: int __db_tas_mutex_unlock __P((DB_ENV *, db_mutex_t));
00200  */
00201 int
00202 __db_tas_mutex_unlock(dbenv, mutex)
00203         DB_ENV *dbenv;
00204         db_mutex_t mutex;
00205 {
00206         DB_MUTEX *mutexp;
00207         DB_MUTEXMGR *mtxmgr;
00208         DB_MUTEXREGION *mtxregion;
00209 
00210         if (!MUTEX_ON(dbenv) || F_ISSET(dbenv, DB_ENV_NOLOCKING))
00211                 return (0);
00212 
00213         mtxmgr = dbenv->mutex_handle;
00214         mtxregion = mtxmgr->reginfo.primary;
00215         mutexp = MUTEXP_SET(mutex);
00216 
00217 #ifdef DIAGNOSTIC
00218         if (!F_ISSET(mutexp, DB_MUTEX_LOCKED)) {
00219                 __db_err(dbenv, "TAS unlock failed: lock already unlocked");
00220                 return (__db_panic(dbenv, EACCES));
00221         }
00222 #endif
00223         F_CLR(mutexp, DB_MUTEX_LOCKED);
00224 
00225         MUTEX_UNSET(&mutexp->tas);
00226 
00227         return (0);
00228 }
00229 
00230 /*
00231  * __db_tas_mutex_destroy --
00232  *      Destroy a mutex.
00233  *
00234  * PUBLIC: int __db_tas_mutex_destroy __P((DB_ENV *, db_mutex_t));
00235  */
00236 int
00237 __db_tas_mutex_destroy(dbenv, mutex)
00238         DB_ENV *dbenv;
00239         db_mutex_t mutex;
00240 {
00241         DB_MUTEX *mutexp;
00242         DB_MUTEXMGR *mtxmgr;
00243         DB_MUTEXREGION *mtxregion;
00244 
00245         if (!MUTEX_ON(dbenv))
00246                 return (0);
00247 
00248         mtxmgr = dbenv->mutex_handle;
00249         mtxregion = mtxmgr->reginfo.primary;
00250         mutexp = MUTEXP_SET(mutex);
00251 
00252         MUTEX_DESTROY(&mutexp->tas);
00253 
00254         return (0);
00255 }

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