| Index: base/synchronization/waitable_event_win.cc
|
| diff --git a/base/synchronization/waitable_event_win.cc b/base/synchronization/waitable_event_win.cc
|
| index d80cabb3ff3ae864fb25f54448885d2c252c5f2b..993dbb1222427137fae077a5c0b9c3acd15bdae3 100644
|
| --- a/base/synchronization/waitable_event_win.cc
|
| +++ b/base/synchronization/waitable_event_win.cc
|
| @@ -7,6 +7,7 @@
|
| #include <windows.h>
|
| #include <stddef.h>
|
|
|
| +#include <algorithm>
|
| #include <utility>
|
|
|
| #include "base/debug/activity_tracker.h"
|
| @@ -44,54 +45,96 @@ void WaitableEvent::Signal() {
|
| }
|
|
|
| bool WaitableEvent::IsSignaled() {
|
| - return TimedWait(TimeDelta());
|
| + DWORD result = WaitForSingleObject(handle_.Get(), 0);
|
| + DCHECK(result == WAIT_OBJECT_0 || result == WAIT_TIMEOUT)
|
| + << "Unexpected WaitForSingleObject result " << result;
|
| + return result == WAIT_OBJECT_0;
|
| }
|
|
|
| void WaitableEvent::Wait() {
|
| + base::ThreadRestrictions::AssertWaitAllowed();
|
| // Record the event that this thread is blocking upon (for hang diagnosis).
|
| base::debug::ScopedEventWaitActivity event_activity(this);
|
|
|
| - base::ThreadRestrictions::AssertWaitAllowed();
|
| DWORD result = WaitForSingleObject(handle_.Get(), INFINITE);
|
| // It is most unexpected that this should ever fail. Help consumers learn
|
| // about it if it should ever fail.
|
| DCHECK_EQ(WAIT_OBJECT_0, result) << "WaitForSingleObject failed";
|
| }
|
|
|
| -bool WaitableEvent::TimedWait(const TimeDelta& max_time) {
|
| +namespace {
|
| +
|
| +// Helper function called from TimedWait and TimedWaitUntil.
|
| +bool WaitUntil(HANDLE handle, const TimeTicks& now, const TimeTicks& end_time) {
|
| + TimeDelta delta = end_time - now;
|
| + DCHECK_GT(delta, TimeDelta());
|
| +
|
| + do {
|
| + // On Windows, waiting for less than 1 ms results in WaitForSingleObject
|
| + // returning promptly which may result in the caller code spinning.
|
| + // We need to ensure that we specify at least the minimally possible 1 ms
|
| + // delay unless the initial timeout was exactly zero.
|
| + delta = std::max(delta, TimeDelta::FromMilliseconds(1));
|
| + // Truncate the timeout to milliseconds.
|
| + DWORD timeout_ms = saturated_cast<DWORD>(delta.InMilliseconds());
|
| + DWORD result = WaitForSingleObject(handle, timeout_ms);
|
| + DCHECK(result == WAIT_OBJECT_0 || result == WAIT_TIMEOUT)
|
| + << "Unexpected WaitForSingleObject result " << result;
|
| + switch (result) {
|
| + case WAIT_OBJECT_0:
|
| + return true;
|
| + case WAIT_TIMEOUT:
|
| + // TimedWait can time out earlier than the specified |timeout| on
|
| + // Windows. To make this consistent with the posix implementation we
|
| + // should guarantee that TimedWait doesn't return earlier than the
|
| + // specified |max_time| and wait again for the remaining time.
|
| + delta = end_time - TimeTicks::Now();
|
| + break;
|
| + }
|
| + } while (delta > TimeDelta());
|
| + return false;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +bool WaitableEvent::TimedWait(const TimeDelta& wait_delta) {
|
| + DCHECK_GE(wait_delta, TimeDelta());
|
| + if (wait_delta.is_zero())
|
| + return IsSignaled();
|
| +
|
| + base::ThreadRestrictions::AssertWaitAllowed();
|
| // Record the event that this thread is blocking upon (for hang diagnosis).
|
| base::debug::ScopedEventWaitActivity event_activity(this);
|
|
|
| - DCHECK_GE(max_time, TimeDelta());
|
| - if (!max_time.is_zero())
|
| - base::ThreadRestrictions::AssertWaitAllowed();
|
| -
|
| - // Truncate the timeout to milliseconds. The API specifies that this method
|
| - // can return in less than |max_time| (when returning false), as the argument
|
| - // is the maximum time that a caller is willing to wait.
|
| - DWORD timeout = saturated_cast<DWORD>(max_time.InMilliseconds());
|
| -
|
| - DWORD result = WaitForSingleObject(handle_.Get(), timeout);
|
| - switch (result) {
|
| - case WAIT_OBJECT_0:
|
| - return true;
|
| - case WAIT_TIMEOUT:
|
| - return false;
|
| - }
|
| - // It is most unexpected that this should ever fail. Help consumers learn
|
| - // about it if it should ever fail.
|
| - NOTREACHED() << "WaitForSingleObject failed";
|
| - return false;
|
| + TimeTicks now(TimeTicks::Now());
|
| + // TimeTicks takes care of overflow including the cases when wait_delta
|
| + // is a maximum value.
|
| + return WaitUntil(handle_.Get(), now, now + wait_delta);
|
| +}
|
| +
|
| +bool WaitableEvent::TimedWaitUntil(const TimeTicks& end_time) {
|
| + if (end_time.is_null())
|
| + return IsSignaled();
|
| +
|
| + base::ThreadRestrictions::AssertWaitAllowed();
|
| + // Record the event that this thread is blocking upon (for hang diagnosis).
|
| + base::debug::ScopedEventWaitActivity event_activity(this);
|
| +
|
| + TimeTicks now(TimeTicks::Now());
|
| + if (end_time <= now)
|
| + return IsSignaled();
|
| +
|
| + return WaitUntil(handle_.Get(), now, end_time);
|
| }
|
|
|
| // static
|
| size_t WaitableEvent::WaitMany(WaitableEvent** events, size_t count) {
|
| DCHECK(count) << "Cannot wait on no events";
|
|
|
| + base::ThreadRestrictions::AssertWaitAllowed();
|
| // Record an event (the first) that this thread is blocking upon.
|
| base::debug::ScopedEventWaitActivity event_activity(events[0]);
|
|
|
| - base::ThreadRestrictions::AssertWaitAllowed();
|
| HANDLE handles[MAXIMUM_WAIT_OBJECTS];
|
| CHECK_LE(count, static_cast<size_t>(MAXIMUM_WAIT_OBJECTS))
|
| << "Can only wait on " << MAXIMUM_WAIT_OBJECTS << " with WaitMany";
|
|
|