michael@0: // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. michael@0: // Use of this source code is governed by a BSD-style license that can be michael@0: // found in the LICENSE file. michael@0: michael@0: #include "base/waitable_event.h" michael@0: michael@0: #include michael@0: #include michael@0: michael@0: #include "base/logging.h" michael@0: #include "base/time.h" michael@0: michael@0: namespace base { michael@0: michael@0: WaitableEvent::WaitableEvent(bool manual_reset, bool signaled) michael@0: : handle_(CreateEvent(NULL, manual_reset, signaled, NULL)) { michael@0: // We're probably going to crash anyways if this is ever NULL, so we might as michael@0: // well make our stack reports more informative by crashing here. michael@0: CHECK(handle_); michael@0: } michael@0: michael@0: WaitableEvent::WaitableEvent(HANDLE handle) michael@0: : handle_(handle) { michael@0: CHECK(handle) << "Tried to create WaitableEvent from NULL handle"; michael@0: } michael@0: michael@0: WaitableEvent::~WaitableEvent() { michael@0: CloseHandle(handle_); michael@0: } michael@0: michael@0: HANDLE WaitableEvent::Release() { michael@0: HANDLE rv = handle_; michael@0: handle_ = INVALID_HANDLE_VALUE; michael@0: return rv; michael@0: } michael@0: michael@0: void WaitableEvent::Reset() { michael@0: ResetEvent(handle_); michael@0: } michael@0: michael@0: void WaitableEvent::Signal() { michael@0: SetEvent(handle_); michael@0: } michael@0: michael@0: bool WaitableEvent::IsSignaled() { michael@0: return TimedWait(TimeDelta::FromMilliseconds(0)); michael@0: } michael@0: michael@0: bool WaitableEvent::Wait() { michael@0: DWORD result = WaitForSingleObject(handle_, INFINITE); michael@0: // It is most unexpected that this should ever fail. Help consumers learn michael@0: // about it if it should ever fail. michael@0: DCHECK(result == WAIT_OBJECT_0) << "WaitForSingleObject failed"; michael@0: return result == WAIT_OBJECT_0; michael@0: } michael@0: michael@0: bool WaitableEvent::TimedWait(const TimeDelta& max_time) { michael@0: DCHECK(max_time >= TimeDelta::FromMicroseconds(0)); michael@0: // Be careful here. TimeDelta has a precision of microseconds, but this API michael@0: // is in milliseconds. If there are 5.5ms left, should the delay be 5 or 6? michael@0: // It should be 6 to avoid returning too early. michael@0: double timeout = ceil(max_time.InMillisecondsF()); michael@0: DWORD result = WaitForSingleObject(handle_, static_cast(timeout)); michael@0: switch (result) { michael@0: case WAIT_OBJECT_0: michael@0: return true; michael@0: case WAIT_TIMEOUT: michael@0: return false; michael@0: } michael@0: // It is most unexpected that this should ever fail. Help consumers learn michael@0: // about it if it should ever fail. michael@0: NOTREACHED() << "WaitForSingleObject failed"; michael@0: return false; michael@0: } michael@0: michael@0: // static michael@0: size_t WaitableEvent::WaitMany(WaitableEvent** events, size_t count) { michael@0: HANDLE handles[MAXIMUM_WAIT_OBJECTS]; michael@0: CHECK(count <= MAXIMUM_WAIT_OBJECTS) michael@0: << "Can only wait on " << MAXIMUM_WAIT_OBJECTS << " with WaitMany"; michael@0: michael@0: for (size_t i = 0; i < count; ++i) michael@0: handles[i] = events[i]->handle(); michael@0: michael@0: DWORD result = michael@0: WaitForMultipleObjects(count, handles, michael@0: FALSE, // don't wait for all the objects michael@0: INFINITE); // no timeout michael@0: if (result < WAIT_OBJECT_0 || result >= WAIT_OBJECT_0 + count) { michael@0: NOTREACHED() << "WaitForMultipleObjects failed: " << GetLastError(); michael@0: return 0; michael@0: } michael@0: michael@0: return result - WAIT_OBJECT_0; michael@0: } michael@0: michael@0: } // namespace base