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 |
| 67 // Helper function called from TimedWait and TimedWaitUntil. |
| 68 bool WaitUntil(HANDLE handle, const TimeTicks& now, const TimeTicks& end_time) { |
| 69 TimeDelta delta = end_time - now; |
| 70 DCHECK_GT(delta, TimeDelta()); |
| 71 |
| 72 do { |
| 73 // On Windows, waiting for less than 1 ms results in WaitForSingleObject |
| 74 // returning promptly which may result in the caller code spinning. |
| 75 // We need to ensure that we specify at least the minimally possible 1 ms |
| 76 // delay unless the initial timeout was exactly zero. |
| 77 delta = std::max(delta, TimeDelta::FromMilliseconds(1)); |
| 78 // Truncate the timeout to milliseconds. |
| 79 DWORD timeout_ms = saturated_cast<DWORD>(delta.InMilliseconds()); |
| 80 DWORD result = WaitForSingleObject(handle, timeout_ms); |
| 81 DCHECK(result == WAIT_OBJECT_0 || result == WAIT_TIMEOUT) |
| 82 << "Unexpected WaitForSingleObject result " << result; |
| 83 switch (result) { |
| 84 case WAIT_OBJECT_0: |
| 85 return true; |
| 86 case WAIT_TIMEOUT: |
| 87 // TimedWait can time out earlier than the specified |timeout| on |
| 88 // Windows. To make this consistent with the posix implementation we |
| 89 // should guarantee that TimedWait doesn't return earlier than the |
| 90 // specified |max_time| and wait again for the remaining time. |
| 91 delta = end_time - TimeTicks::Now(); |
| 92 break; |
| 93 } |
| 94 } while (delta > TimeDelta()); |
| 95 return false; |
| 96 } |
| 97 |
| 98 } // namespace |
| 99 |
| 100 bool WaitableEvent::TimedWait(const TimeDelta& wait_delta) { |
| 101 DCHECK_GE(wait_delta, TimeDelta()); |
| 102 if (wait_delta.is_zero()) |
| 103 return IsSignaled(); |
| 104 |
| 105 base::ThreadRestrictions::AssertWaitAllowed(); |
62 // Record the event that this thread is blocking upon (for hang diagnosis). | 106 // Record the event that this thread is blocking upon (for hang diagnosis). |
63 base::debug::ScopedEventWaitActivity event_activity(this); | 107 base::debug::ScopedEventWaitActivity event_activity(this); |
64 | 108 |
65 DCHECK_GE(max_time, TimeDelta()); | 109 TimeTicks now(TimeTicks::Now()); |
66 if (!max_time.is_zero()) | 110 // TimeTicks takes care of overflow including the cases when wait_delta |
67 base::ThreadRestrictions::AssertWaitAllowed(); | 111 // is a maximum value. |
| 112 return WaitUntil(handle_.Get(), now, now + wait_delta); |
| 113 } |
68 | 114 |
69 // Truncate the timeout to milliseconds. The API specifies that this method | 115 bool WaitableEvent::TimedWaitUntil(const TimeTicks& end_time) { |
70 // can return in less than |max_time| (when returning false), as the argument | 116 if (end_time.is_null()) |
71 // is the maximum time that a caller is willing to wait. | 117 return IsSignaled(); |
72 DWORD timeout = saturated_cast<DWORD>(max_time.InMilliseconds()); | |
73 | 118 |
74 DWORD result = WaitForSingleObject(handle_.Get(), timeout); | 119 base::ThreadRestrictions::AssertWaitAllowed(); |
75 switch (result) { | 120 // Record the event that this thread is blocking upon (for hang diagnosis). |
76 case WAIT_OBJECT_0: | 121 base::debug::ScopedEventWaitActivity event_activity(this); |
77 return true; | 122 |
78 case WAIT_TIMEOUT: | 123 TimeTicks now(TimeTicks::Now()); |
79 return false; | 124 if (end_time <= now) |
80 } | 125 return IsSignaled(); |
81 // It is most unexpected that this should ever fail. Help consumers learn | 126 |
82 // about it if it should ever fail. | 127 return WaitUntil(handle_.Get(), now, end_time); |
83 NOTREACHED() << "WaitForSingleObject failed"; | |
84 return false; | |
85 } | 128 } |
86 | 129 |
87 // static | 130 // static |
88 size_t WaitableEvent::WaitMany(WaitableEvent** events, size_t count) { | 131 size_t WaitableEvent::WaitMany(WaitableEvent** events, size_t count) { |
89 DCHECK(count) << "Cannot wait on no events"; | 132 DCHECK(count) << "Cannot wait on no events"; |
90 | 133 |
| 134 base::ThreadRestrictions::AssertWaitAllowed(); |
91 // Record an event (the first) that this thread is blocking upon. | 135 // Record an event (the first) that this thread is blocking upon. |
92 base::debug::ScopedEventWaitActivity event_activity(events[0]); | 136 base::debug::ScopedEventWaitActivity event_activity(events[0]); |
93 | 137 |
94 base::ThreadRestrictions::AssertWaitAllowed(); | |
95 HANDLE handles[MAXIMUM_WAIT_OBJECTS]; | 138 HANDLE handles[MAXIMUM_WAIT_OBJECTS]; |
96 CHECK_LE(count, static_cast<size_t>(MAXIMUM_WAIT_OBJECTS)) | 139 CHECK_LE(count, static_cast<size_t>(MAXIMUM_WAIT_OBJECTS)) |
97 << "Can only wait on " << MAXIMUM_WAIT_OBJECTS << " with WaitMany"; | 140 << "Can only wait on " << MAXIMUM_WAIT_OBJECTS << " with WaitMany"; |
98 | 141 |
99 for (size_t i = 0; i < count; ++i) | 142 for (size_t i = 0; i < count; ++i) |
100 handles[i] = events[i]->handle(); | 143 handles[i] = events[i]->handle(); |
101 | 144 |
102 // The cast is safe because count is small - see the CHECK above. | 145 // The cast is safe because count is small - see the CHECK above. |
103 DWORD result = | 146 DWORD result = |
104 WaitForMultipleObjects(static_cast<DWORD>(count), | 147 WaitForMultipleObjects(static_cast<DWORD>(count), |
105 handles, | 148 handles, |
106 FALSE, // don't wait for all the objects | 149 FALSE, // don't wait for all the objects |
107 INFINITE); // no timeout | 150 INFINITE); // no timeout |
108 if (result >= WAIT_OBJECT_0 + count) { | 151 if (result >= WAIT_OBJECT_0 + count) { |
109 DPLOG(FATAL) << "WaitForMultipleObjects failed"; | 152 DPLOG(FATAL) << "WaitForMultipleObjects failed"; |
110 return 0; | 153 return 0; |
111 } | 154 } |
112 | 155 |
113 return result - WAIT_OBJECT_0; | 156 return result - WAIT_OBJECT_0; |
114 } | 157 } |
115 | 158 |
116 } // namespace base | 159 } // namespace base |
OLD | NEW |