summaryrefslogtreecommitdiff
path: root/src/os_win/os_mtx_cond.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/os_win/os_mtx_cond.c')
-rw-r--r--src/os_win/os_mtx_cond.c43
1 files changed, 30 insertions, 13 deletions
diff --git a/src/os_win/os_mtx_cond.c b/src/os_win/os_mtx_cond.c
index 79c62ccd7f2..0001c6c2322 100644
--- a/src/os_win/os_mtx_cond.c
+++ b/src/os_win/os_mtx_cond.c
@@ -13,8 +13,7 @@
* Allocate and initialize a condition variable.
*/
int
-__wt_cond_alloc(WT_SESSION_IMPL *session,
- const char *name, bool is_signalled, WT_CONDVAR **condp)
+__wt_cond_alloc(WT_SESSION_IMPL *session, const char *name, WT_CONDVAR **condp)
{
WT_CONDVAR *cond;
@@ -26,7 +25,7 @@ __wt_cond_alloc(WT_SESSION_IMPL *session,
InitializeConditionVariable(&cond->cond);
cond->name = name;
- cond->waiters = is_signalled ? -1 : 0;
+ cond->waiters = 0;
*condp = cond;
return (0);
@@ -38,8 +37,8 @@ __wt_cond_alloc(WT_SESSION_IMPL *session,
* out period expires, let the caller know.
*/
void
-__wt_cond_wait_signal(
- WT_SESSION_IMPL *session, WT_CONDVAR *cond, uint64_t usecs, bool *signalled)
+__wt_cond_wait_signal(WT_SESSION_IMPL *session, WT_CONDVAR *cond,
+ uint64_t usecs, bool (*run_func)(WT_SESSION_IMPL *), bool *signalled)
{
BOOL sleepret;
DWORD milliseconds, windows_error;
@@ -59,8 +58,26 @@ __wt_cond_wait_signal(
EnterCriticalSection(&cond->mtx);
locked = true;
+ /*
+ * It's possible to race with threads waking us up. That's not a problem
+ * if there are multiple wakeups because the next wakeup will get us, or
+ * if we're only pausing for a short period. It's a problem if there's
+ * only a single wakeup, our waker is likely waiting for us to exit.
+ * After acquiring the mutex (so we're guaranteed to be awakened by any
+ * future wakeup call), optionally check if we're OK to keep running.
+ * This won't ensure our caller won't just loop and call us again, but
+ * at least it's not our fault.
+ *
+ * Assert we're not waiting longer than a second if not checking the
+ * run status.
+ */
+ WT_ASSERT(session, run_func != NULL || usecs <= WT_MILLION);
+
+ if (run_func != NULL && !run_func(session))
+ goto skipping;
+
if (usecs > 0) {
- milliseconds64 = usecs / 1000;
+ milliseconds64 = usecs / WT_THOUSAND;
/*
* Check for 32-bit unsigned integer overflow
@@ -90,7 +107,7 @@ __wt_cond_wait_signal(
if (sleepret == 0) {
windows_error = __wt_getlasterror();
if (windows_error == ERROR_TIMEOUT) {
- *signalled = false;
+skipping: *signalled = false;
sleepret = 1;
}
}
@@ -117,17 +134,17 @@ void
__wt_cond_signal(WT_SESSION_IMPL *session, WT_CONDVAR *cond)
{
WT_DECL_RET;
- bool locked;
-
- locked = false;
__wt_verbose(session, WT_VERB_MUTEX, "signal %s", cond->name);
/*
- * Our callers are often setting flags to cause a thread to exit. Add
- * a barrier to ensure the flags are seen by the threads.
+ * Our callers often set flags to cause a thread to exit. Add a barrier
+ * to ensure exit flags are seen by the sleeping threads, otherwise we
+ * can wake up a thread, it immediately goes back to sleep, and we'll
+ * hang. Use a full barrier (we may not write before waiting on thread
+ * join).
*/
- WT_WRITE_BARRIER();
+ WT_FULL_BARRIER();
/*
* Fast path if we are in (or can enter), a state where the next waiter