#include "db_config.h"
#include "db_int.h"
#define LOAD_ACTUAL_MUTEX_CODE
#include "dbinc/mutex_int.h"
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);
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);
}
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
ms = 1;
max_ms = F_ISSET(mutexp, DB_MUTEX_LOGICAL_LOCK) ? 10 : 25;
#endif
loop:
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
if (F_ISSET(mutexp, DB_MUTEX_LOCKED) ||
!MUTEX_SET(&mutexp->tas)) {
#ifdef MUTEX_PAUSE
MUTEX_PAUSE
#endif
continue;
}
#ifdef HAVE_MUTEX_HPPA_MSEM_INIT
if (F_ISSET(mutexp, DB_MUTEX_LOCKED)) {
F_SET(mutexp, DB_MUTEX_LOCKED);
dbenv->thread_id(dbenv, &mutexp->pid, &mutexp->tid);
goto relock;
}
#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
if (F_ISSET(dbenv, DB_ENV_YIELDCPU))
__os_yield(env, 0, 0);
#endif
return (0);
}
#ifdef HAVE_MUTEX_HYBRID
__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
PANIC_CHECK(env);
goto loop;
}
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);
}
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);
return (0);
}