summaryrefslogtreecommitdiff
path: root/src/mutex/mut_win32.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mutex/mut_win32.c')
-rw-r--r--src/mutex/mut_win32.c188
1 files changed, 145 insertions, 43 deletions
diff --git a/src/mutex/mut_win32.c b/src/mutex/mut_win32.c
index 07d5a8dd..270e03fb 100644
--- a/src/mutex/mut_win32.c
+++ b/src/mutex/mut_win32.c
@@ -1,7 +1,7 @@
/*
* See the file LICENSE for redistribution information.
*
- * Copyright (c) 2002, 2012 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2015 Oracle and/or its affiliates. All rights reserved.
*
* $Id$
*/
@@ -92,6 +92,9 @@ __db_win32_mutex_lock_int(env, mutex, timeout, wait)
db_timespec now, tempspec, timeoutspec;
db_timeout_t time_left;
int ret;
+#ifdef DIAGNOSTIC
+ char buf[DB_THREADID_STRLEN];
+#endif
#ifdef MUTEX_DIAG
LARGE_INTEGER now;
#endif
@@ -143,8 +146,10 @@ loop: /* Attempt to acquire the mutex mutex_tas_spins times, if waiting. */
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);
+ ip->dbth_state == THREAD_FAILCHK) {
+ ret = DB_RUNRECOVERY;
+ goto failed;
+ }
}
if (!wait)
return (DB_LOCK_NOTGRANTED);
@@ -155,15 +160,20 @@ loop: /* Attempt to acquire the mutex mutex_tas_spins times, if waiting. */
MUTEX_PAUSE
continue;
}
-
+#ifdef HAVE_FAILCHK_BROADCAST
+ if (F_ISSET(mutexp, DB_MUTEX_OWNER_DEAD)) {
+ MUTEX_UNSET(&mutexp->tas);
+ goto died;
+ }
+#endif
#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));
+ ret = __env_panic(env, EACCES);
+ goto failed;
}
#endif
F_SET(mutexp, DB_MUTEX_LOCKED);
@@ -179,11 +189,12 @@ loop: /* Attempt to acquire the mutex mutex_tas_spins times, if waiting. */
CloseHandle(event);
InterlockedDecrement(&mutexp->nwaiters);
#ifdef MUTEX_DIAG
+ /* "ret" was set by WaitForSingleObject(). */
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"),
+ "[%lld]: Lost signal on mutex %p, "
+ "id %d, ms %d\n", "%lld %p %d %d"),
diag_now.QuadPart, mutexp, mutexp->id, ms);
}
#endif
@@ -210,11 +221,8 @@ loop: /* Attempt to acquire the mutex mutex_tas_spins times, if waiting. */
if (timeout != 0) {
timespecclear(&now);
if (__clock_expired(env, &now, &timeoutspec)) {
- if (event != NULL) {
- CloseHandle(event);
- InterlockedDecrement(&mutexp->nwaiters);
- }
- return (DB_TIMEOUT);
+ ret = DB_TIMEOUT;
+ goto failed;
}
/* Reduce the event wait if the timeout would happen first. */
tempspec = timeoutspec;
@@ -228,24 +236,41 @@ loop: /* Attempt to acquire the mutex mutex_tas_spins times, if waiting. */
#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);
+ "[%lld]: Waiting on mutex %p, id %d\n",
+ "%lld %p %d"), diag_now.QuadPart, mutexp, mutexp->id);
#endif
InterlockedIncrement(&mutexp->nwaiters);
- if ((ret = get_handle(env, mutexp, &event)) != 0)
- goto err;
+ if ((ret = get_handle(env, mutexp, &event)) != 0) {
+ InterlockedDecrement(&mutexp->nwaiters);
+ goto syserr;
+ }
}
if ((ret = WaitForSingleObject(event, ms)) == WAIT_FAILED) {
ret = __os_get_syserr();
- goto err;
+ goto syserr;
}
if ((ms <<= 1) > MS_PER_SEC)
ms = MS_PER_SEC;
+#ifdef HAVE_FAILCHK_BROADCAST
+ if (F_ISSET(mutexp, DB_MUTEX_OWNER_DEAD) &&
+ !F_ISSET(dbenv, DB_ENV_FAILCHK)) {
+died:
+ ret = __mutex_died(env, mutex);
+ goto failed;
+ }
+#endif
PANIC_CHECK(env);
goto loop;
-err: __db_syserr(env, ret, DB_STR("2006", "Win32 lock failed"));
+failed:
+ if (event != NULL) {
+ CloseHandle(event);
+ InterlockedDecrement(&mutexp->nwaiters);
+ }
+ return (ret);
+
+syserr: __db_syserr(env, ret, DB_STR("2006", "Win32 lock failed"));
return (__env_panic(env, __os_posix_err(ret)));
}
@@ -266,6 +291,12 @@ __db_win32_mutex_init(env, mutex, flags)
mutexp = MUTEXP_SET(env, mutex);
mutexp->id = ((getpid() & 0xffff) << 16) ^ P_TO_UINT32(mutexp);
F_SET(mutexp, flags);
+ /*
+ * See WINCE_ATOMIC_MAGIC definition for details.
+ * Use sharecount, because the value just needs to be a db_atomic_t
+ * memory mapped onto the same page as those being Interlocked*.
+ */
+ WINCE_ATOMIC_MAGIC(&mutexp->sharecount);
return (0);
}
@@ -315,9 +346,11 @@ __db_win32_mutex_readlock_int(env, mutex, nowait)
DB_MUTEXMGR *mtxmgr;
DB_MUTEXREGION *mtxregion;
HANDLE event;
+ MUTEX_STATE *state;
u_int32_t nspins;
- int ms, ret;
- long exch_ret, mtx_val;
+ int max_ms, ms, ret;
+ long mtx_val;
+
#ifdef MUTEX_DIAG
LARGE_INTEGER diag_now;
#endif
@@ -342,11 +375,23 @@ __db_win32_mutex_readlock_int(env, mutex, nowait)
event = NULL;
ms = 50;
ret = 0;
+
+ state = NULL;
+ if (env->thr_hashtab != NULL && (ret = __mutex_record_lock(env,
+ mutex, MUTEX_ACTION_INTEND_SHARE, &state)) != 0)
+ return (ret);
+#ifdef HAVE_FAILCHK_BROADCAST
/*
- * This needs to be initialized, since if mutexp->tas
- * is write locked on the first pass, it needs a value.
+ * Limit WaitForSingleObject() sleeps to at most the failchk timeout,
+ * and least 1 millisecond. When failchk broadcasting is not
+ * supported check at least every second.
*/
- exch_ret = 0;
+ if (dbenv->mutex_failchk_timeout != 0 &&
+ (max_ms = (dbenv->mutex_failchk_timeout / US_PER_MS)) == 0)
+ max_ms = 1;
+ else
+#endif
+ max_ms = MS_PER_SEC;
loop: /* Attempt to acquire the resource for N spins. */
for (nspins =
@@ -357,9 +402,10 @@ loop: /* Attempt to acquire the resource for N spins. */
*/
retry: mtx_val = atomic_read(&mutexp->sharecount);
if (mtx_val == MUTEX_SHARE_ISEXCLUSIVE) {
- if (nowait)
- return (DB_LOCK_NOTGRANTED);
-
+ if (nowait) {
+ ret = DB_LOCK_NOTGRANTED;
+ goto failed;
+ }
continue;
} else if (!atomic_compare_exchange(env, &mutexp->sharecount,
mtx_val, mtx_val + 1)) {
@@ -370,6 +416,15 @@ retry: mtx_val = atomic_read(&mutexp->sharecount);
MUTEX_PAUSE
goto retry;
}
+#ifdef HAVE_FAILCHK_BROADCAST
+ if (F_ISSET(mutexp, DB_MUTEX_OWNER_DEAD) &&
+ !F_ISSET(dbenv, DB_ENV_FAILCHK)) {
+ InterlockedDecrement(
+ (interlocked_val)&mutexp->sharecount);
+ ret = __mutex_died(env, mutex);
+ goto failed;
+ }
+#endif
#ifdef HAVE_STATISTICS
if (event == NULL)
@@ -384,12 +439,14 @@ retry: mtx_val = atomic_read(&mutexp->sharecount);
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"),
+ "[%lld]: Lost signal on mutex %p, "
+ "id %d, ms %d\n", "%lld %p %d %d"),
diag_now.QuadPart, mutexp, mutexp->id, ms);
}
#endif
}
+ if (state != NULL)
+ state->action = MUTEX_ACTION_SHARED;
#ifdef DIAGNOSTIC
/*
@@ -404,17 +461,17 @@ retry: mtx_val = atomic_read(&mutexp->sharecount);
}
/*
- * Yield the processor; wait 50 ms initially, up to 1 second. This
- * loop is needed to work around a race where the signal from the
- * unlocking thread gets lost. We start at 50 ms because it's unlikely
- * to happen often and we want to avoid wasting CPU.
+ * Yield the processor; wait 50 ms initially, up to 1 second or the
+ * failchk timeout. This loop works around a race where the signal from
+ * the unlocking thread gets lost. We start at 50 ms because it's
+ * unlikely to happen often and we want to avoid wasting CPU.
*/
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);
+ "[%lld]: Waiting on mutex %p, id %d\n",
+ "%lld %p %d"), diag_now.QuadPart, mutexp, mutexp->id);
#endif
InterlockedIncrement(&mutexp->nwaiters);
if ((ret = get_handle(env, mutexp, &event)) != 0)
@@ -424,12 +481,32 @@ retry: mtx_val = atomic_read(&mutexp->sharecount);
ret = __os_get_syserr();
goto err;
}
- if ((ms <<= 1) > MS_PER_SEC)
- ms = MS_PER_SEC;
+
+#ifdef HAVE_FAILCHK_BROADCAST
+ if (F_ISSET(mutexp, DB_MUTEX_OWNER_DEAD) &&
+ !F_ISSET(dbenv, DB_ENV_FAILCHK)) {
+ (void)atomic_compare_exchange(env,
+ &mutexp->sharecount, mtx_val, mtx_val - 1);
+ ret = __mutex_died(env, mutex);
+ goto failed;
+ }
+#endif
PANIC_CHECK(env);
+
+ if ((ms <<= 1) > max_ms)
+ ms = max_ms;
goto loop;
+failed:
+ if (event != NULL) {
+ CloseHandle(event);
+ InterlockedDecrement(&mutexp->nwaiters);
+ }
+ if (state != NULL)
+ state->action = MUTEX_ACTION_UNLOCKED;
+ return (ret);
+
err: __db_syserr(env, ret, DB_STR("2009",
"Win32 read lock failed"));
return (__env_panic(env, __os_posix_err(ret)));
@@ -482,7 +559,8 @@ __db_win32_mutex_unlock(env, mutex)
DB_ENV *dbenv;
DB_MUTEX *mutexp;
HANDLE event;
- int ret;
+ int ret, sharecount;
+ char description[DB_MUTEX_DESCRIBE_STRLEN];
#ifdef MUTEX_DIAG
LARGE_INTEGER diag_now;
#endif
@@ -510,6 +588,16 @@ __db_win32_mutex_unlock(env, mutex)
*/
#ifdef HAVE_SHARED_LATCHES
if (F_ISSET(mutexp, DB_MUTEX_SHARED)) {
+ sharecount = atomic_read(&mutexp->sharecount);
+ if (sharecount == 0) {
+ if (!PANIC_ISSET(env)) {
+ __db_errx(env, DB_STR_A("2071",
+ "Shared unlock %s: already unlocked", "%s"),
+ __mutex_describe(env, mutex, description));
+ return (DB_RUNRECOVERY);
+ }
+ return (__env_panic(env, EACCES));
+ }
if (F_ISSET(mutexp, DB_MUTEX_LOCKED)) {
F_CLR(mutexp, DB_MUTEX_LOCKED);
if ((ret = InterlockedExchange(
@@ -519,12 +607,26 @@ __db_win32_mutex_unlock(env, mutex)
ret = DB_RUNRECOVERY;
goto err;
}
- } else if (InterlockedDecrement(
- (interlocked_val)(&atomic_read(&mutexp->sharecount))) > 0)
- return (0);
+ } else {
+ if (env->thr_hashtab != NULL &&
+ (ret = __mutex_record_unlock(env, mutex)) != 0)
+ return (ret);
+ if (InterlockedDecrement((interlocked_val)
+ (&atomic_read(&mutexp->sharecount))) > 0)
+ return (0);
+ }
} else
#endif
{
+ if (!F_ISSET(mutexp, DB_MUTEX_LOCKED)) {
+ if (!PANIC_ISSET(env)) {
+ __db_errx(env, DB_STR_A("2072",
+ "Unlock %s: already unlocked", "%s"),
+ __mutex_describe(env, mutex, description));
+ return (DB_RUNRECOVERY);
+ }
+ return (__env_panic(env, EACCES));
+ }
F_CLR(mutexp, DB_MUTEX_LOCKED);
MUTEX_UNSET(&mutexp->tas);
}
@@ -536,8 +638,8 @@ __db_win32_mutex_unlock(env, mutex)
#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);
+ "[%lld]: Signalling mutex %p, id %d\n",
+ "%lld %p %d"), diag_now.QuadPart, mutexp, mutexp->id);
#endif
if (!PulseEvent(event)) {
ret = __os_get_syserr();