#include "db_config.h"
#define LOAD_ACTUAL_MUTEX_CODE
#include "db_int.h"
#include "dbinc/atomic.h"
#include "dbinc/mutex_int.h"
static _TCHAR hex_digits[] = _T("0123456789abcdef");
static __inline int get_handle(env, mutexp, eventp)
ENV *env;
DB_MUTEX *mutexp;
HANDLE *eventp;
{
_TCHAR idbuf[] = _T("db.m00000000");
_TCHAR *p = idbuf + 12;
int ret = 0;
u_int32_t id;
for (id = (mutexp)->id; id != 0; id >>= 4)
*--p = hex_digits[id & 0xf];
#ifndef DB_WINCE
if (DB_GLOBAL(win_sec_attr) == NULL) {
InitializeSecurityDescriptor(&DB_GLOBAL(win_default_sec_desc),
SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl(&DB_GLOBAL(win_default_sec_desc),
TRUE, 0, FALSE);
DB_GLOBAL(win_default_sec_attr).nLength =
sizeof(SECURITY_ATTRIBUTES);
DB_GLOBAL(win_default_sec_attr).bInheritHandle = FALSE;
DB_GLOBAL(win_default_sec_attr).lpSecurityDescriptor =
&DB_GLOBAL(win_default_sec_desc);
DB_GLOBAL(win_sec_attr) = &DB_GLOBAL(win_default_sec_attr);
}
#endif
if ((*eventp = CreateEvent(DB_GLOBAL(win_sec_attr),
FALSE, FALSE, idbuf)) == NULL) {
ret = __os_get_syserr();
__db_syserr(env, ret, DB_STR("2002",
"Win32 create event failed"));
}
return (ret);
}
static __inline int
__db_win32_mutex_lock_int(env, mutex, timeout, wait)
ENV *env;
db_mutex_t mutex;
db_timeout_t timeout;
int wait;
{
DB_ENV *dbenv;
DB_MUTEX *mutexp;
DB_MUTEXMGR *mtxmgr;
DB_MUTEXREGION *mtxregion;
DB_THREAD_INFO *ip;
HANDLE event;
u_int32_t ms, nspins;
db_timespec now, tempspec, timeoutspec;
db_timeout_t time_left;
int ret;
#ifdef MUTEX_DIAG
LARGE_INTEGER now;
#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(env, mutex);
CHECK_MTX_THREAD(env, mutexp);
if (timeout != 0) {
timespecclear(&timeoutspec);
__clock_set_expires(env, &timeoutspec, timeout);
}
WINCE_ATOMIC_MAGIC(&mutexp->sharecount);
event = NULL;
ms = 50;
ret = 0;
ip = NULL;
loop:
for (nspins =
mtxregion->stat.st_mutex_tas_spins; nspins > 0; --nspins) {
if (MUTEXP_IS_BUSY(mutexp) || !MUTEXP_ACQUIRE(mutexp)) {
if (F_ISSET(dbenv, DB_ENV_FAILCHK) &&
ip == NULL && dbenv->is_alive(dbenv,
mutexp->pid, mutexp->tid, 0) == 0) {
ret = __env_set_state(env, &ip, THREAD_VERIFY);
if (ret != 0 ||
ip->dbth_state == THREAD_FAILCHK)
return (DB_RUNRECOVERY);
}
if (!wait)
return (DB_LOCK_NOTGRANTED);
MUTEX_PAUSE
continue;
}
#ifdef DIAGNOSTIC
if (F_ISSET(mutexp, DB_MUTEX_LOCKED)) {
char buf[DB_THREADID_STRLEN];
__db_errx(env, DB_STR_A("2003",
"Win32 lock failed: mutex already locked by %s",
"%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 HAVE_STATISTICS
if (event == NULL)
++mutexp->mutex_set_nowait;
else
++mutexp->mutex_set_wait;
#endif
if (event != NULL) {
CloseHandle(event);
InterlockedDecrement(&mutexp->nwaiters);
#ifdef MUTEX_DIAG
if (ret != WAIT_OBJECT_0) {
QueryPerformanceCounter(&diag_now);
printf(DB_STR_A("2004",
"[%I64d]: Lost signal on mutex %p, "
"id %d, ms %d\n", "%I64d %p %d %d"),
diag_now.QuadPart, mutexp, mutexp->id, ms);
}
#endif
}
#ifdef DIAGNOSTIC
if (F_ISSET(dbenv, DB_ENV_YIELDCPU))
__os_yield(env, 0, 0);
#endif
return (0);
}
if (timeout != 0) {
timespecclear(&now);
if (__clock_expired(env, &now, &timeoutspec)) {
if (event != NULL) {
CloseHandle(event);
InterlockedDecrement(&mutexp->nwaiters);
}
return (DB_TIMEOUT);
}
tempspec = timeoutspec;
timespecsub(&tempspec, &now);
DB_TIMESPEC_TO_TIMEOUT(time_left, &tempspec, 0);
time_left /= US_PER_MS;
if (ms > time_left)
ms = time_left;
}
if (event == NULL) {
#ifdef MUTEX_DIAG
QueryPerformanceCounter(&diag_now);
printf(DB_STR_A("2005",
"[%I64d]: Waiting on mutex %p, id %d\n",
"%I64d %p %d"), diag_now.QuadPart, mutexp, mutexp->id);
#endif
InterlockedIncrement(&mutexp->nwaiters);
if ((ret = get_handle(env, mutexp, &event)) != 0)
goto err;
}
if ((ret = WaitForSingleObject(event, ms)) == WAIT_FAILED) {
ret = __os_get_syserr();
goto err;
}
if ((ms <<= 1) > MS_PER_SEC)
ms = MS_PER_SEC;
PANIC_CHECK(env);
goto loop;
err: __db_syserr(env, ret, DB_STR("2006", "Win32 lock failed"));
return (__env_panic(env, __os_posix_err(ret)));
}
int
__db_win32_mutex_init(env, mutex, flags)
ENV *env;
db_mutex_t mutex;
u_int32_t flags;
{
DB_MUTEX *mutexp;
mutexp = MUTEXP_SET(env, mutex);
mutexp->id = ((getpid() & 0xffff) << 16) ^ P_TO_UINT32(mutexp);
F_SET(mutexp, flags);
return (0);
}
int
__db_win32_mutex_lock(env, mutex, timeout)
ENV *env;
db_mutex_t mutex;
db_timeout_t timeout;
{
return (__db_win32_mutex_lock_int(env, mutex, timeout, 1));
}
int
__db_win32_mutex_trylock(env, mutex)
ENV *env;
db_mutex_t mutex;
{
return (__db_win32_mutex_lock_int(env, mutex, 0));
}
#if defined(HAVE_SHARED_LATCHES)
int
__db_win32_mutex_readlock_int(env, mutex, nowait)
ENV *env;
db_mutex_t mutex;
int nowait;
{
DB_ENV *dbenv;
DB_MUTEX *mutexp;
DB_MUTEXMGR *mtxmgr;
DB_MUTEXREGION *mtxregion;
HANDLE event;
u_int32_t nspins;
int ms, ret;
long exch_ret, mtx_val;
#ifdef MUTEX_DIAG
LARGE_INTEGER diag_now;
#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(env, mutex);
CHECK_MTX_THREAD(env, mutexp);
WINCE_ATOMIC_MAGIC(&mutexp->sharecount);
event = NULL;
ms = 50;
ret = 0;
exch_ret = 0;
loop:
for (nspins =
mtxregion->stat.st_mutex_tas_spins; nspins > 0; --nspins) {
retry: mtx_val = atomic_read(&mutexp->sharecount);
if (mtx_val == MUTEX_SHARE_ISEXCLUSIVE) {
if (nowait)
return (DB_LOCK_NOTGRANTED);
continue;
} else if (!atomic_compare_exchange(env, &mutexp->sharecount,
mtx_val, mtx_val + 1)) {
MUTEX_PAUSE
goto retry;
}
#ifdef HAVE_STATISTICS
if (event == NULL)
++mutexp->mutex_set_rd_nowait;
else
++mutexp->mutex_set_rd_wait;
#endif
if (event != NULL) {
CloseHandle(event);
InterlockedDecrement(&mutexp->nwaiters);
#ifdef MUTEX_DIAG
if (ret != WAIT_OBJECT_0) {
QueryPerformanceCounter(&diag_now);
printf(DB_STR_A("2007",
"[%I64d]: Lost signal on mutex %p, "
"id %d, ms %d\n", "%I64d %p %d %d"),
diag_now.QuadPart, mutexp, mutexp->id, ms);
}
#endif
}
#ifdef DIAGNOSTIC
if (F_ISSET(dbenv, DB_ENV_YIELDCPU))
__os_yield(env, 0, 0);
#endif
return (0);
}
if (event == NULL) {
#ifdef MUTEX_DIAG
QueryPerformanceCounter(&diag_now);
printf(DB_STR_A("2008",
"[%I64d]: Waiting on mutex %p, id %d\n",
"%I64d %p %d"), diag_now.QuadPart, mutexp, mutexp->id);
#endif
InterlockedIncrement(&mutexp->nwaiters);
if ((ret = get_handle(env, mutexp, &event)) != 0)
goto err;
}
if ((ret = WaitForSingleObject(event, ms)) == WAIT_FAILED) {
ret = __os_get_syserr();
goto err;
}
if ((ms <<= 1) > MS_PER_SEC)
ms = MS_PER_SEC;
PANIC_CHECK(env);
goto loop;
err: __db_syserr(env, ret, DB_STR("2009",
"Win32 read lock failed"));
return (__env_panic(env, __os_posix_err(ret)));
}
int
__db_win32_mutex_readlock(env, mutex)
ENV *env;
db_mutex_t mutex;
{
return (__db_win32_mutex_readlock_int(env, mutex, 0));
}
int
__db_win32_mutex_tryreadlock(env, mutex)
ENV *env;
db_mutex_t mutex;
{
return (__db_win32_mutex_readlock_int(env, mutex, 1));
}
#endif
int
__db_win32_mutex_unlock(env, mutex)
ENV *env;
db_mutex_t mutex;
{
DB_ENV *dbenv;
DB_MUTEX *mutexp;
HANDLE event;
int ret;
#ifdef MUTEX_DIAG
LARGE_INTEGER diag_now;
#endif
dbenv = env->dbenv;
if (!MUTEX_ON(env) || F_ISSET(dbenv, DB_ENV_NOLOCKING))
return (0);
mutexp = MUTEXP_SET(env, mutex);
#ifdef DIAGNOSTIC
if (!MUTEXP_IS_BUSY(mutexp) || !(F_ISSET(mutexp, DB_MUTEX_SHARED) ||
F_ISSET(mutexp, DB_MUTEX_LOCKED))) {
__db_errx(env, DB_STR_A("2010",
"Win32 unlock failed: lock already unlocked: mutex %d busy %d",
"%d %d"), mutex, MUTEXP_BUSY_FIELD(mutexp));
return (__env_panic(env, EACCES));
}
#endif
#ifdef HAVE_SHARED_LATCHES
if (F_ISSET(mutexp, DB_MUTEX_SHARED)) {
if (F_ISSET(mutexp, DB_MUTEX_LOCKED)) {
F_CLR(mutexp, DB_MUTEX_LOCKED);
if ((ret = InterlockedExchange(
(interlocked_val)(&atomic_read(
&mutexp->sharecount)), 0)) !=
MUTEX_SHARE_ISEXCLUSIVE) {
ret = DB_RUNRECOVERY;
goto err;
}
} else if (InterlockedDecrement(
(interlocked_val)(&atomic_read(&mutexp->sharecount))) > 0)
return (0);
} else
#endif
{
F_CLR(mutexp, DB_MUTEX_LOCKED);
MUTEX_UNSET(&mutexp->tas);
}
if (mutexp->nwaiters > 0) {
if ((ret = get_handle(env, mutexp, &event)) != 0)
goto err;
#ifdef MUTEX_DIAG
QueryPerformanceCounter(&diag_now);
printf(DB_STR_A("2011",
"[%I64d]: Signalling mutex %p, id %d\n",
"%I64d %p %d"), diag_now.QuadPart, mutexp, mutexp->id);
#endif
if (!PulseEvent(event)) {
ret = __os_get_syserr();
CloseHandle(event);
goto err;
}
CloseHandle(event);
}
return (0);
err: __db_syserr(env, ret, DB_STR("2012", "Win32 unlock failed"));
return (__env_panic(env, __os_posix_err(ret)));
}
int
__db_win32_mutex_destroy(env, mutex)
ENV *env;
db_mutex_t mutex;
{
return (0);
}
#ifndef DB_WINCE
int
db_env_set_win_security(sa)
SECURITY_ATTRIBUTES *sa;
{
DB_GLOBAL(win_sec_attr) = sa;
return (0);
}
#endif