#include "db_config.h"
#include "db_int.h"
int
__mutex_alloc(env, alloc_id, flags, indxp)
ENV *env;
int alloc_id;
u_int32_t flags;
db_mutex_t *indxp;
{
*indxp = MUTEX_INVALID;
if (alloc_id != MTX_APPLICATION && alloc_id != MTX_MUTEX_TEST &&
(F_ISSET(env->dbenv, DB_ENV_NOLOCKING) ||
(!F_ISSET(env, ENV_THREAD) &&
(LF_ISSET(DB_MUTEX_PROCESS_ONLY) ||
F_ISSET(env, ENV_PRIVATE)))))
return (0);
if (F_ISSET(env, ENV_PRIVATE))
LF_SET(DB_MUTEX_PROCESS_ONLY);
if (!MUTEX_ON(env)) {
__db_errx(env, DB_STR("2033",
"Mutex allocated before mutex region."));
return (__env_panic(env, EINVAL));
}
return (__mutex_alloc_int(env, 1, alloc_id, flags, indxp));
}
int
__mutex_alloc_int(env, locksys, alloc_id, flags, indxp)
ENV *env;
int locksys, alloc_id;
u_int32_t flags;
db_mutex_t *indxp;
{
DB_ENV *dbenv;
DB_MUTEX *mutexp;
DB_MUTEXMGR *mtxmgr;
DB_MUTEXREGION *mtxregion;
db_mutex_t i;
size_t len;
u_int32_t cnt;
int ret;
dbenv = env->dbenv;
mtxmgr = env->mutex_handle;
mtxregion = mtxmgr->reginfo.primary;
ret = 0;
if (locksys)
MUTEX_SYSTEM_LOCK(env);
if (mtxregion->mutex_next == MUTEX_INVALID) {
if (mtxregion->stat.st_mutex_max != 0 &&
mtxregion->stat.st_mutex_cnt >=
mtxregion->stat.st_mutex_max) {
nomem: __db_errx(env, DB_STR("2034",
"unable to allocate memory for mutex; resize mutex region"));
if (locksys)
MUTEX_SYSTEM_UNLOCK(env);
return (ret == 0 ? ENOMEM : ret);
}
cnt = mtxregion->stat.st_mutex_cnt / 2;
if (cnt < 8)
cnt = 8;
if (mtxregion->stat.st_mutex_max != 0 &&
mtxregion->stat.st_mutex_cnt + cnt >
mtxregion->stat.st_mutex_max)
cnt = mtxregion->stat.st_mutex_max -
mtxregion->stat.st_mutex_cnt;
if (F_ISSET(env, ENV_PRIVATE)) {
F_SET(&mtxmgr->reginfo, REGION_TRACKED);
while (__env_alloc(&mtxmgr->reginfo,
(cnt * mtxregion->mutex_size) +
mtxregion->stat.st_mutex_align, &i) != 0)
if ((cnt >> 1) == 0)
break;
F_CLR(&mtxmgr->reginfo, REGION_TRACKED);
i = (db_mutex_t)ALIGNP_INC(i,
mtxregion->stat.st_mutex_align);
} else {
len = cnt * mtxregion->mutex_size;
if ((ret = __env_alloc_extend(&mtxmgr->reginfo,
R_ADDR(&mtxmgr->reginfo,
mtxregion->mutex_off_alloc), &len)) != 0)
goto nomem;
cnt = (u_int32_t)(len / mtxregion->mutex_size);
i = mtxregion->stat.st_mutex_cnt + 1;
}
if (cnt == 0)
goto nomem;
mutexp = MUTEXP_SET(env, i);
mtxregion->stat.st_mutex_free = cnt;
mtxregion->mutex_next = i;
mtxregion->stat.st_mutex_cnt += cnt;
while (--cnt > 0) {
mutexp->flags = 0;
if (F_ISSET(env, ENV_PRIVATE))
mutexp->mutex_next_link =
(uintptr_t)(mutexp + 1);
else
mutexp->mutex_next_link = ++i;
mutexp++;
}
mutexp->flags = 0;
mutexp->mutex_next_link = MUTEX_INVALID;
}
*indxp = mtxregion->mutex_next;
mutexp = MUTEXP_SET(env, *indxp);
DB_ASSERT(env,
((uintptr_t)mutexp & (dbenv->mutex_align - 1)) == 0);
mtxregion->mutex_next = mutexp->mutex_next_link;
--mtxregion->stat.st_mutex_free;
++mtxregion->stat.st_mutex_inuse;
if (mtxregion->stat.st_mutex_inuse > mtxregion->stat.st_mutex_inuse_max)
mtxregion->stat.st_mutex_inuse_max =
mtxregion->stat.st_mutex_inuse;
if (locksys)
MUTEX_SYSTEM_UNLOCK(env);
memset(mutexp, 0, sizeof(*mutexp));
F_SET(mutexp, DB_MUTEX_ALLOCATED |
LF_ISSET(DB_MUTEX_LOGICAL_LOCK |
DB_MUTEX_PROCESS_ONLY | DB_MUTEX_SHARED));
if (LF_ISSET(DB_MUTEX_PROCESS_ONLY))
dbenv->thread_id(dbenv, &mutexp->pid, NULL);
#ifdef HAVE_STATISTICS
mutexp->alloc_id = alloc_id;
#else
COMPQUIET(alloc_id, 0);
#endif
if ((ret = __mutex_init(env, *indxp, flags)) != 0)
(void)__mutex_free_int(env, locksys, indxp);
return (ret);
}
int
__mutex_free(env, indxp)
ENV *env;
db_mutex_t *indxp;
{
if (!MUTEX_ON(env) || *indxp == MUTEX_INVALID)
return (0);
return (__mutex_free_int(env, 1, indxp));
}
int
__mutex_free_int(env, locksys, indxp)
ENV *env;
int locksys;
db_mutex_t *indxp;
{
DB_MUTEX *mutexp;
DB_MUTEXMGR *mtxmgr;
DB_MUTEXREGION *mtxregion;
db_mutex_t mutex;
int ret;
mutex = *indxp;
*indxp = MUTEX_INVALID;
mtxmgr = env->mutex_handle;
mtxregion = mtxmgr->reginfo.primary;
mutexp = MUTEXP_SET(env, mutex);
DB_ASSERT(env, F_ISSET(mutexp, DB_MUTEX_ALLOCATED));
F_CLR(mutexp, DB_MUTEX_ALLOCATED);
ret = __mutex_destroy(env, mutex);
if (locksys)
MUTEX_SYSTEM_LOCK(env);
mutexp->mutex_next_link = mtxregion->mutex_next;
mtxregion->mutex_next = mutex;
++mtxregion->stat.st_mutex_free;
--mtxregion->stat.st_mutex_inuse;
if (locksys)
MUTEX_SYSTEM_UNLOCK(env);
return (ret);
}
int
__mutex_refresh(env, mutex)
ENV *env;
db_mutex_t mutex;
{
DB_MUTEX *mutexp;
u_int32_t flags;
int ret;
mutexp = MUTEXP_SET(env, mutex);
flags = mutexp->flags;
if ((ret = __mutex_destroy(env, mutex)) == 0) {
memset(mutexp, 0, sizeof(*mutexp));
F_SET(mutexp, DB_MUTEX_ALLOCATED |
LF_ISSET(DB_MUTEX_LOGICAL_LOCK |
DB_MUTEX_PROCESS_ONLY | DB_MUTEX_SHARED));
LF_CLR(DB_MUTEX_LOCKED);
ret = __mutex_init(env, mutex, flags);
}
return (ret);
}