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 |