Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/synchronization/waitable_event.h" | 5 #include "base/synchronization/waitable_event.h" |
| 6 | 6 |
| 7 #include <windows.h> | 7 #include <windows.h> |
| 8 #include <stddef.h> | 8 #include <stddef.h> |
| 9 | 9 |
| 10 #include <algorithm> | |
| 10 #include <utility> | 11 #include <utility> |
| 11 | 12 |
| 12 #include "base/debug/activity_tracker.h" | 13 #include "base/debug/activity_tracker.h" |
| 13 #include "base/logging.h" | 14 #include "base/logging.h" |
| 14 #include "base/numerics/safe_conversions.h" | 15 #include "base/numerics/safe_conversions.h" |
| 15 #include "base/threading/thread_restrictions.h" | 16 #include "base/threading/thread_restrictions.h" |
| 16 #include "base/time/time.h" | 17 #include "base/time/time.h" |
| 17 | 18 |
| 18 namespace base { | 19 namespace base { |
| 19 | 20 |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 37 | 38 |
| 38 void WaitableEvent::Reset() { | 39 void WaitableEvent::Reset() { |
| 39 ResetEvent(handle_.Get()); | 40 ResetEvent(handle_.Get()); |
| 40 } | 41 } |
| 41 | 42 |
| 42 void WaitableEvent::Signal() { | 43 void WaitableEvent::Signal() { |
| 43 SetEvent(handle_.Get()); | 44 SetEvent(handle_.Get()); |
| 44 } | 45 } |
| 45 | 46 |
| 46 bool WaitableEvent::IsSignaled() { | 47 bool WaitableEvent::IsSignaled() { |
| 47 return TimedWait(TimeDelta()); | 48 DWORD result = WaitForSingleObject(handle_.Get(), 0); |
| 49 DCHECK(result == WAIT_OBJECT_0 || result == WAIT_TIMEOUT) | |
| 50 << "Unexpected WaitForSingleObject result " << result; | |
| 51 return result == WAIT_OBJECT_0; | |
| 48 } | 52 } |
| 49 | 53 |
| 50 void WaitableEvent::Wait() { | 54 void WaitableEvent::Wait() { |
| 55 base::ThreadRestrictions::AssertWaitAllowed(); | |
| 51 // Record the event that this thread is blocking upon (for hang diagnosis). | 56 // Record the event that this thread is blocking upon (for hang diagnosis). |
| 52 base::debug::ScopedEventWaitActivity event_activity(this); | 57 base::debug::ScopedEventWaitActivity event_activity(this); |
| 53 | 58 |
| 54 base::ThreadRestrictions::AssertWaitAllowed(); | |
| 55 DWORD result = WaitForSingleObject(handle_.Get(), INFINITE); | 59 DWORD result = WaitForSingleObject(handle_.Get(), INFINITE); |
| 56 // It is most unexpected that this should ever fail. Help consumers learn | 60 // It is most unexpected that this should ever fail. Help consumers learn |
| 57 // about it if it should ever fail. | 61 // about it if it should ever fail. |
| 58 DCHECK_EQ(WAIT_OBJECT_0, result) << "WaitForSingleObject failed"; | 62 DCHECK_EQ(WAIT_OBJECT_0, result) << "WaitForSingleObject failed"; |
| 59 } | 63 } |
| 60 | 64 |
| 61 bool WaitableEvent::TimedWait(const TimeDelta& max_time) { | 65 namespace { |
| 66 // Helper function called from TimedWait and TimedWaitUntil. | |
| 67 bool WaitUntil(HANDLE handle, const TimeTicks& now, const TimeTicks& end_time) { | |
| 68 TimeDelta delta = end_time - now; | |
| 69 DCHECK_GT(delta, TimeDelta()); | |
| 70 | |
| 71 do { | |
| 72 // On Windows, waiting for less than 1 ms results in WaitForSingleObject | |
| 73 // returning promptly which may result in the caller code spinning. | |
| 74 // We need to ensure that we specify at least the minimally possible 1 ms | |
| 75 // delay unless the initial timeout was exactly zero. | |
| 76 delta = std::max(delta, TimeDelta::FromMilliseconds(1)); | |
| 77 // Truncate the timeout to milliseconds. | |
| 78 DWORD timeout_ms = saturated_cast<DWORD>(delta.InMilliseconds()); | |
| 79 DWORD result = WaitForSingleObject(handle, timeout_ms); | |
| 80 DCHECK(result == WAIT_OBJECT_0 || result == WAIT_TIMEOUT) | |
| 81 << "Unexpected WaitForSingleObject result " << result; | |
| 82 switch (result) { | |
| 83 case WAIT_OBJECT_0: | |
| 84 return true; | |
| 85 case WAIT_TIMEOUT: | |
| 86 // TimedWait can time out earlier than the specified |timeout| on | |
| 87 // Windows. To make this consistent with the posix implementation we | |
| 88 // should guarantee that TimedWait doesn't return earlier than the | |
| 89 // specified |max_time| and wait again for the remaining time. | |
| 90 delta = end_time - TimeTicks::Now(); | |
| 91 break; | |
| 92 } | |
| 93 } while (delta > TimeDelta()); | |
| 94 return false; | |
| 95 } | |
| 96 } // namespace | |
|
danakj
2016/11/29 02:46:45
nit: whitespace lines around the namespace { and }
stanisc
2016/11/29 22:33:21
Done.
| |
| 97 | |
| 98 bool WaitableEvent::TimedWait(const TimeDelta& max_delta) { | |
|
danakj
2016/11/29 02:46:45
same name nit
stanisc
2016/11/29 22:33:21
Done.
| |
| 99 DCHECK_GE(max_delta, TimeDelta()); | |
| 100 if (max_delta.is_zero()) | |
| 101 return IsSignaled(); | |
| 102 | |
| 103 base::ThreadRestrictions::AssertWaitAllowed(); | |
| 62 // Record the event that this thread is blocking upon (for hang diagnosis). | 104 // Record the event that this thread is blocking upon (for hang diagnosis). |
| 63 base::debug::ScopedEventWaitActivity event_activity(this); | 105 base::debug::ScopedEventWaitActivity event_activity(this); |
| 64 | 106 |
| 65 DCHECK_GE(max_time, TimeDelta()); | 107 TimeTicks now(TimeTicks::Now()); |
| 66 if (!max_time.is_zero()) | 108 // TimeTicks takes care of overflow including the cases when max_delta |
| 67 base::ThreadRestrictions::AssertWaitAllowed(); | 109 // is a maximum value. |
| 110 return WaitUntil(handle_.Get(), now, now + max_delta); | |
| 111 } | |
| 68 | 112 |
| 69 // Truncate the timeout to milliseconds. The API specifies that this method | 113 bool WaitableEvent::TimedWaitUntil(const TimeTicks& end_time) { |
| 70 // can return in less than |max_time| (when returning false), as the argument | 114 if (end_time.is_null()) |
| 71 // is the maximum time that a caller is willing to wait. | 115 return IsSignaled(); |
| 72 DWORD timeout = saturated_cast<DWORD>(max_time.InMilliseconds()); | |
| 73 | 116 |
| 74 DWORD result = WaitForSingleObject(handle_.Get(), timeout); | 117 base::ThreadRestrictions::AssertWaitAllowed(); |
| 75 switch (result) { | 118 // Record the event that this thread is blocking upon (for hang diagnosis). |
| 76 case WAIT_OBJECT_0: | 119 base::debug::ScopedEventWaitActivity event_activity(this); |
| 77 return true; | 120 |
| 78 case WAIT_TIMEOUT: | 121 TimeTicks now(TimeTicks::Now()); |
| 79 return false; | 122 if (end_time <= now) |
| 80 } | 123 return IsSignaled(); |
| 81 // It is most unexpected that this should ever fail. Help consumers learn | 124 |
| 82 // about it if it should ever fail. | 125 return WaitUntil(handle_.Get(), now, end_time); |
| 83 NOTREACHED() << "WaitForSingleObject failed"; | |
| 84 return false; | |
| 85 } | 126 } |
| 86 | 127 |
| 87 // static | 128 // static |
| 88 size_t WaitableEvent::WaitMany(WaitableEvent** events, size_t count) { | 129 size_t WaitableEvent::WaitMany(WaitableEvent** events, size_t count) { |
| 89 DCHECK(count) << "Cannot wait on no events"; | 130 DCHECK(count) << "Cannot wait on no events"; |
| 90 | 131 |
| 132 base::ThreadRestrictions::AssertWaitAllowed(); | |
| 91 // Record an event (the first) that this thread is blocking upon. | 133 // Record an event (the first) that this thread is blocking upon. |
| 92 base::debug::ScopedEventWaitActivity event_activity(events[0]); | 134 base::debug::ScopedEventWaitActivity event_activity(events[0]); |
| 93 | 135 |
| 94 base::ThreadRestrictions::AssertWaitAllowed(); | |
| 95 HANDLE handles[MAXIMUM_WAIT_OBJECTS]; | 136 HANDLE handles[MAXIMUM_WAIT_OBJECTS]; |
| 96 CHECK_LE(count, static_cast<size_t>(MAXIMUM_WAIT_OBJECTS)) | 137 CHECK_LE(count, static_cast<size_t>(MAXIMUM_WAIT_OBJECTS)) |
| 97 << "Can only wait on " << MAXIMUM_WAIT_OBJECTS << " with WaitMany"; | 138 << "Can only wait on " << MAXIMUM_WAIT_OBJECTS << " with WaitMany"; |
| 98 | 139 |
| 99 for (size_t i = 0; i < count; ++i) | 140 for (size_t i = 0; i < count; ++i) |
| 100 handles[i] = events[i]->handle(); | 141 handles[i] = events[i]->handle(); |
| 101 | 142 |
| 102 // The cast is safe because count is small - see the CHECK above. | 143 // The cast is safe because count is small - see the CHECK above. |
| 103 DWORD result = | 144 DWORD result = |
| 104 WaitForMultipleObjects(static_cast<DWORD>(count), | 145 WaitForMultipleObjects(static_cast<DWORD>(count), |
| 105 handles, | 146 handles, |
| 106 FALSE, // don't wait for all the objects | 147 FALSE, // don't wait for all the objects |
| 107 INFINITE); // no timeout | 148 INFINITE); // no timeout |
| 108 if (result >= WAIT_OBJECT_0 + count) { | 149 if (result >= WAIT_OBJECT_0 + count) { |
| 109 DPLOG(FATAL) << "WaitForMultipleObjects failed"; | 150 DPLOG(FATAL) << "WaitForMultipleObjects failed"; |
| 110 return 0; | 151 return 0; |
| 111 } | 152 } |
| 112 | 153 |
| 113 return result - WAIT_OBJECT_0; | 154 return result - WAIT_OBJECT_0; |
| 114 } | 155 } |
| 115 | 156 |
| 116 } // namespace base | 157 } // namespace base |
| OLD | NEW |