Import BSDDB 4.7.25 (as of svn r89086)
This commit is contained in:
293
mutex/mut_tas.c
Normal file
293
mutex/mut_tas.c
Normal file
@@ -0,0 +1,293 @@
|
||||
/*-
|
||||
* See the file LICENSE for redistribution information.
|
||||
*
|
||||
* Copyright (c) 1996,2008 Oracle. All rights reserved.
|
||||
*
|
||||
* $Id: mut_tas.c 63573 2008-05-23 21:43:21Z trent.nelson $
|
||||
*/
|
||||
|
||||
#include "db_config.h"
|
||||
|
||||
#include "db_int.h"
|
||||
|
||||
/*
|
||||
* This is where we load in architecture/compiler specific mutex code.
|
||||
*/
|
||||
#define LOAD_ACTUAL_MUTEX_CODE
|
||||
#include "dbinc/mutex_int.h"
|
||||
|
||||
/*
|
||||
* __db_tas_mutex_init --
|
||||
* Initialize a test-and-set mutex.
|
||||
*
|
||||
* PUBLIC: int __db_tas_mutex_init __P((ENV *, db_mutex_t, u_int32_t));
|
||||
*/
|
||||
int
|
||||
__db_tas_mutex_init(env, mutex, flags)
|
||||
ENV *env;
|
||||
db_mutex_t mutex;
|
||||
u_int32_t flags;
|
||||
{
|
||||
DB_ENV *dbenv;
|
||||
DB_MUTEX *mutexp;
|
||||
DB_MUTEXMGR *mtxmgr;
|
||||
DB_MUTEXREGION *mtxregion;
|
||||
int ret;
|
||||
|
||||
COMPQUIET(flags, 0);
|
||||
|
||||
dbenv = env->dbenv;
|
||||
mtxmgr = env->mutex_handle;
|
||||
mtxregion = mtxmgr->reginfo.primary;
|
||||
mutexp = MUTEXP_SET(mutex);
|
||||
|
||||
/* Check alignment. */
|
||||
if (((uintptr_t)mutexp & (dbenv->mutex_align - 1)) != 0) {
|
||||
__db_errx(env, "TAS: mutex not appropriately aligned");
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
if (MUTEX_INIT(&mutexp->tas)) {
|
||||
ret = __os_get_syserr();
|
||||
__db_syserr(env, ret, "TAS: mutex initialize");
|
||||
return (__os_posix_err(ret));
|
||||
}
|
||||
#ifdef HAVE_MUTEX_HYBRID
|
||||
if ((ret = __db_pthread_mutex_init(env,
|
||||
mutex, flags | DB_MUTEX_SELF_BLOCK)) != 0)
|
||||
return (ret);
|
||||
#endif
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_tas_mutex_lock
|
||||
* Lock on a mutex, blocking if necessary.
|
||||
*
|
||||
* PUBLIC: int __db_tas_mutex_lock __P((ENV *, db_mutex_t));
|
||||
*/
|
||||
int
|
||||
__db_tas_mutex_lock(env, mutex)
|
||||
ENV *env;
|
||||
db_mutex_t mutex;
|
||||
{
|
||||
DB_ENV *dbenv;
|
||||
DB_MUTEX *mutexp;
|
||||
DB_MUTEXMGR *mtxmgr;
|
||||
DB_MUTEXREGION *mtxregion;
|
||||
u_int32_t nspins;
|
||||
#ifdef HAVE_MUTEX_HYBRID
|
||||
int ret;
|
||||
#else
|
||||
u_long ms, max_ms;
|
||||
#endif
|
||||
dbenv = env->dbenv;
|
||||
|
||||
if (!MUTEX_ON(env) || F_ISSET(dbenv, DB_ENV_NOLOCKING))
|
||||
return (0);
|
||||
|
||||
mtxmgr = env->mutex_handle;
|
||||
mtxregion = mtxmgr->reginfo.primary;
|
||||
mutexp = MUTEXP_SET(mutex);
|
||||
|
||||
CHECK_MTX_THREAD(env, mutexp);
|
||||
|
||||
#ifdef HAVE_STATISTICS
|
||||
if (F_ISSET(mutexp, DB_MUTEX_LOCKED))
|
||||
++mutexp->mutex_set_wait;
|
||||
else
|
||||
++mutexp->mutex_set_nowait;
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_MUTEX_HYBRID
|
||||
/*
|
||||
* Wait 1ms initially, up to 10ms for mutexes backing logical database
|
||||
* locks, and up to 25 ms for mutual exclusion data structure mutexes.
|
||||
* SR: #7675
|
||||
*/
|
||||
ms = 1;
|
||||
max_ms = F_ISSET(mutexp, DB_MUTEX_LOGICAL_LOCK) ? 10 : 25;
|
||||
#endif
|
||||
|
||||
loop: /* Attempt to acquire the resource for N spins. */
|
||||
for (nspins =
|
||||
mtxregion->stat.st_mutex_tas_spins; nspins > 0; --nspins) {
|
||||
#ifdef HAVE_MUTEX_HPPA_MSEM_INIT
|
||||
relock:
|
||||
#endif
|
||||
#ifdef HAVE_MUTEX_S390_CC_ASSEMBLY
|
||||
tsl_t zero = 0;
|
||||
#endif
|
||||
/*
|
||||
* Avoid interlocked instructions until they're likely to
|
||||
* succeed.
|
||||
*/
|
||||
if (F_ISSET(mutexp, DB_MUTEX_LOCKED) ||
|
||||
!MUTEX_SET(&mutexp->tas)) {
|
||||
/*
|
||||
* Some systems (notably those with newer Intel CPUs)
|
||||
* need a small pause here. [#6975]
|
||||
*/
|
||||
#ifdef MUTEX_PAUSE
|
||||
MUTEX_PAUSE
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef HAVE_MUTEX_HPPA_MSEM_INIT
|
||||
/*
|
||||
* HP semaphores are unlocked automatically when a holding
|
||||
* process exits. If the mutex appears to be locked
|
||||
* (F_ISSET(DB_MUTEX_LOCKED)) but we got here, assume this
|
||||
* has happened. Set the pid and tid into the mutex and
|
||||
* lock again. (The default state of the mutexes used to
|
||||
* block in __lock_get_internal is locked, so exiting with
|
||||
* a locked mutex is reasonable behavior for a process that
|
||||
* happened to initialize or use one of them.)
|
||||
*/
|
||||
if (F_ISSET(mutexp, DB_MUTEX_LOCKED)) {
|
||||
F_SET(mutexp, DB_MUTEX_LOCKED);
|
||||
dbenv->thread_id(dbenv, &mutexp->pid, &mutexp->tid);
|
||||
goto relock;
|
||||
}
|
||||
/*
|
||||
* If we make it here, the mutex isn't locked, the diagnostic
|
||||
* won't fire, and we were really unlocked by someone calling
|
||||
* the DB mutex unlock function.
|
||||
*/
|
||||
#endif
|
||||
#ifdef DIAGNOSTIC
|
||||
if (F_ISSET(mutexp, DB_MUTEX_LOCKED)) {
|
||||
char buf[DB_THREADID_STRLEN];
|
||||
__db_errx(env,
|
||||
"TAS lock failed: lock currently in use: ID: %s",
|
||||
dbenv->thread_id_string(dbenv,
|
||||
mutexp->pid, mutexp->tid, buf));
|
||||
return (__env_panic(env, EACCES));
|
||||
}
|
||||
#endif
|
||||
F_SET(mutexp, DB_MUTEX_LOCKED);
|
||||
dbenv->thread_id(dbenv, &mutexp->pid, &mutexp->tid);
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
/*
|
||||
* We want to switch threads as often as possible. Yield
|
||||
* every time we get a mutex to ensure contention.
|
||||
*/
|
||||
if (F_ISSET(dbenv, DB_ENV_YIELDCPU))
|
||||
__os_yield(env, 0, 0);
|
||||
#endif
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Wait for the lock to become available. */
|
||||
#ifdef HAVE_MUTEX_HYBRID
|
||||
/*
|
||||
* By yielding here we can get the other thread to give up the
|
||||
* mutex before calling the more expensive library mutex call.
|
||||
* Tests have shown this to be a big win when there is contention.
|
||||
*/
|
||||
__os_yield(env, 0, 0);
|
||||
if (!F_ISSET(mutexp, DB_MUTEX_LOCKED))
|
||||
goto loop;
|
||||
if ((ret = __db_pthread_mutex_lock(env, mutex)) != 0)
|
||||
return (ret);
|
||||
#else
|
||||
__os_yield(env, 0, ms * US_PER_MS);
|
||||
if ((ms <<= 1) > max_ms)
|
||||
ms = max_ms;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We're spinning. The environment might be hung, and somebody else
|
||||
* has already recovered it. The first thing recovery does is panic
|
||||
* the environment. Check to see if we're never going to get this
|
||||
* mutex.
|
||||
*/
|
||||
PANIC_CHECK(env);
|
||||
|
||||
goto loop;
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_tas_mutex_unlock --
|
||||
* Release a mutex.
|
||||
*
|
||||
* PUBLIC: int __db_tas_mutex_unlock __P((ENV *, db_mutex_t));
|
||||
*/
|
||||
int
|
||||
__db_tas_mutex_unlock(env, mutex)
|
||||
ENV *env;
|
||||
db_mutex_t mutex;
|
||||
{
|
||||
DB_ENV *dbenv;
|
||||
DB_MUTEX *mutexp;
|
||||
DB_MUTEXMGR *mtxmgr;
|
||||
DB_MUTEXREGION *mtxregion;
|
||||
#ifdef HAVE_MUTEX_HYBRID
|
||||
int ret;
|
||||
#endif
|
||||
dbenv = env->dbenv;
|
||||
|
||||
if (!MUTEX_ON(env) || F_ISSET(dbenv, DB_ENV_NOLOCKING))
|
||||
return (0);
|
||||
|
||||
mtxmgr = env->mutex_handle;
|
||||
mtxregion = mtxmgr->reginfo.primary;
|
||||
mutexp = MUTEXP_SET(mutex);
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
if (!F_ISSET(mutexp, DB_MUTEX_LOCKED)) {
|
||||
__db_errx(env, "TAS unlock failed: lock already unlocked");
|
||||
return (__env_panic(env, EACCES));
|
||||
}
|
||||
#endif
|
||||
|
||||
F_CLR(mutexp, DB_MUTEX_LOCKED);
|
||||
#ifdef HAVE_MUTEX_HYBRID
|
||||
MUTEX_MEMBAR(mutexp->flags);
|
||||
|
||||
if (mutexp->wait &&
|
||||
(ret = __db_pthread_mutex_unlock(env, mutex)) != 0)
|
||||
return (ret);
|
||||
#endif
|
||||
MUTEX_UNSET(&mutexp->tas);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* __db_tas_mutex_destroy --
|
||||
* Destroy a mutex.
|
||||
*
|
||||
* PUBLIC: int __db_tas_mutex_destroy __P((ENV *, db_mutex_t));
|
||||
*/
|
||||
int
|
||||
__db_tas_mutex_destroy(env, mutex)
|
||||
ENV *env;
|
||||
db_mutex_t mutex;
|
||||
{
|
||||
DB_MUTEX *mutexp;
|
||||
DB_MUTEXMGR *mtxmgr;
|
||||
DB_MUTEXREGION *mtxregion;
|
||||
#ifdef HAVE_MUTEX_HYBRID
|
||||
int ret;
|
||||
#endif
|
||||
|
||||
if (!MUTEX_ON(env))
|
||||
return (0);
|
||||
|
||||
mtxmgr = env->mutex_handle;
|
||||
mtxregion = mtxmgr->reginfo.primary;
|
||||
mutexp = MUTEXP_SET(mutex);
|
||||
|
||||
MUTEX_DESTROY(&mutexp->tas);
|
||||
|
||||
#ifdef HAVE_MUTEX_HYBRID
|
||||
if ((ret = __db_pthread_mutex_destroy(env, mutex)) != 0)
|
||||
return (ret);
|
||||
#endif
|
||||
|
||||
COMPQUIET(mutexp, NULL); /* MUTEX_DESTROY may not be defined. */
|
||||
return (0);
|
||||
}
|
||||
Reference in New Issue
Block a user