/* * __wt_cond_wait_signal -- * Wait on a mutex, optionally timing out. If we get it * before the time out period expires, let the caller know. */ int __wt_cond_wait_signal( WT_SESSION_IMPL *session, WT_CONDVAR *cond, uint64_t usecs, bool *signalled) { struct timespec ts; WT_DECL_RET; bool locked; locked = false; /* Fast path if already signalled. */ *signalled = true; if (__wt_atomic_addi32(&cond->waiters, 1) == 0) return (0); /* * !!! * This function MUST handle a NULL session handle. */ if (session != NULL) { WT_RET(__wt_verbose(session, WT_VERB_MUTEX, "wait %s cond (%p)", cond->name, cond)); WT_STAT_FAST_CONN_INCR(session, cond_wait); } WT_ERR(pthread_mutex_lock(&cond->mtx)); locked = true; if (usecs > 0) { WT_ERR(__wt_epoch(session, &ts)); ts.tv_sec += (time_t) (((uint64_t)ts.tv_nsec + 1000 * usecs) / WT_BILLION); ts.tv_nsec = (long) (((uint64_t)ts.tv_nsec + 1000 * usecs) % WT_BILLION); ret = pthread_cond_timedwait(&cond->cond, &cond->mtx, &ts); } else ret = pthread_cond_wait(&cond->cond, &cond->mtx); /* * Check pthread_cond_wait() return for EINTR, ETIME and * ETIMEDOUT, some systems return these errors. */ if (ret == EINTR || #ifdef ETIME ret == ETIME || #endif ret == ETIMEDOUT) { *signalled = false; ret = 0; } (void)__wt_atomic_subi32(&cond->waiters, 1); err: if (locked) WT_TRET(pthread_mutex_unlock(&cond->mtx)); if (ret == 0) return (0); WT_RET_MSG(session, ret, "pthread_cond_wait"); }
/* * __wt_cond_wait_signal -- * Wait on a mutex, optionally timing out. If we get it before the time * out period expires, let the caller know. */ void __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; bool locked; uint64_t milliseconds64; locked = false; /* Fast path if already signalled. */ *signalled = true; if (__wt_atomic_addi32(&cond->waiters, 1) == 0) return; __wt_verbose(session, WT_VERB_MUTEX, "wait %s", cond->name); WT_STAT_CONN_INCR(session, cond_wait); 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 / WT_THOUSAND; /* * Check for 32-bit unsigned integer overflow * INFINITE is max unsigned int on Windows */ if (milliseconds64 >= INFINITE) milliseconds64 = INFINITE - 1; milliseconds = (DWORD)milliseconds64; /* * 0 would mean the CV sleep becomes a TryCV which we do not * want */ if (milliseconds == 0) milliseconds = 1; sleepret = SleepConditionVariableCS( &cond->cond, &cond->mtx, milliseconds); } else sleepret = SleepConditionVariableCS( &cond->cond, &cond->mtx, INFINITE); /* * SleepConditionVariableCS returns non-zero on success, 0 on timeout * or failure. */ if (sleepret == 0) { windows_error = __wt_getlasterror(); if (windows_error == ERROR_TIMEOUT) { skipping: *signalled = false; sleepret = 1; } } (void)__wt_atomic_subi32(&cond->waiters, 1); if (locked) LeaveCriticalSection(&cond->mtx); if (sleepret != 0) return; __wt_err(session, __wt_map_windows_error(windows_error), "SleepConditionVariableCS: %s: %s", cond->name, __wt_formatmessage(session, windows_error)); WT_PANIC_MSG(session, __wt_map_windows_error(windows_error), "SleepConditionVariableCS: %s", cond->name); }
/* * __wt_cond_wait_signal -- * Wait on a mutex, optionally timing out. If we get it * before the time out period expires, let the caller know. */ int __wt_cond_wait_signal( WT_SESSION_IMPL *session, WT_CONDVAR *cond, uint64_t usecs, bool *signalled) { BOOL sleepret; DWORD milliseconds, windows_error; bool locked; uint64_t milliseconds64; locked = false; /* Fast path if already signalled. */ *signalled = true; if (__wt_atomic_addi32(&cond->waiters, 1) == 0) return (0); /* * !!! * This function MUST handle a NULL session handle. */ if (session != NULL) { WT_RET(__wt_verbose(session, WT_VERB_MUTEX, "wait %s cond (%p)", cond->name, cond)); WT_STAT_FAST_CONN_INCR(session, cond_wait); } EnterCriticalSection(&cond->mtx); locked = true; if (usecs > 0) { milliseconds64 = usecs / 1000; /* * Check for 32-bit unsigned integer overflow * INFINITE is max unsigned int on Windows */ if (milliseconds64 >= INFINITE) milliseconds64 = INFINITE - 1; milliseconds = (DWORD)milliseconds64; /* * 0 would mean the CV sleep becomes a TryCV which we do not * want */ if (milliseconds == 0) milliseconds = 1; sleepret = SleepConditionVariableCS( &cond->cond, &cond->mtx, milliseconds); } else sleepret = SleepConditionVariableCS( &cond->cond, &cond->mtx, INFINITE); /* * SleepConditionVariableCS returns non-zero on success, 0 on timeout * or failure. */ if (sleepret == 0) { windows_error = __wt_getlasterror(); if (windows_error == ERROR_TIMEOUT) { *signalled = false; sleepret = 1; } } (void)__wt_atomic_subi32(&cond->waiters, 1); if (locked) LeaveCriticalSection(&cond->mtx); if (sleepret != 0) return (0); __wt_errx(session, "SleepConditionVariableCS: %s", __wt_formatmessage(session, windows_error)); return (__wt_map_windows_error(windows_error)); }
/* * __wt_cond_wait_signal -- * Wait on a mutex, optionally timing out. If we get it * before the time out period expires, let the caller know. */ int __wt_cond_wait_signal( WT_SESSION_IMPL *session, WT_CONDVAR *cond, uint64_t usecs, bool *signalled) { DWORD err, milliseconds; WT_DECL_RET; uint64_t milliseconds64; bool locked; locked = false; /* Fast path if already signalled. */ *signalled = true; if (__wt_atomic_addi32(&cond->waiters, 1) == 0) return (0); /* * !!! * This function MUST handle a NULL session handle. */ if (session != NULL) { WT_RET(__wt_verbose(session, WT_VERB_MUTEX, "wait %s cond (%p)", cond->name, cond)); WT_STAT_FAST_CONN_INCR(session, cond_wait); } EnterCriticalSection(&cond->mtx); locked = true; if (usecs > 0) { milliseconds64 = usecs / 1000; /* * Check for 32-bit unsigned integer overflow * INFINITE is max unsigned int on Windows */ if (milliseconds64 >= INFINITE) milliseconds64 = INFINITE - 1; milliseconds = (DWORD)milliseconds64; /* * 0 would mean the CV sleep becomes a TryCV which we do not * want */ if (milliseconds == 0) milliseconds = 1; ret = SleepConditionVariableCS( &cond->cond, &cond->mtx, milliseconds); } else ret = SleepConditionVariableCS( &cond->cond, &cond->mtx, INFINITE); /* * SleepConditionVariableCS returns non-zero on success, 0 on timeout * or failure. Check for timeout, else convert to a WiredTiger error * value and fail. */ if (ret == 0) { if ((err = GetLastError()) == ERROR_TIMEOUT) *signalled = false; else ret = __wt_errno(); } else ret = 0; (void)__wt_atomic_subi32(&cond->waiters, 1); if (locked) LeaveCriticalSection(&cond->mtx); if (ret == 0) return (0); WT_RET_MSG(session, ret, "SleepConditionVariableCS"); }