OLD | NEW |
---|---|
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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/waitable_event.h" | 5 #include "base/waitable_event.h" |
6 | 6 |
7 #include "base/condition_variable.h" | 7 #include "base/condition_variable.h" |
8 #include "base/lock.h" | 8 #include "base/lock.h" |
9 #include "base/message_loop.h" | 9 #include "base/message_loop.h" |
10 | 10 |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
69 const bool result = kernel_->signaled_; | 69 const bool result = kernel_->signaled_; |
70 if (result && !kernel_->manual_reset_) | 70 if (result && !kernel_->manual_reset_) |
71 kernel_->signaled_ = false; | 71 kernel_->signaled_ = false; |
72 return result; | 72 return result; |
73 } | 73 } |
74 | 74 |
75 // ----------------------------------------------------------------------------- | 75 // ----------------------------------------------------------------------------- |
76 // Synchronous waits | 76 // Synchronous waits |
77 | 77 |
78 // ----------------------------------------------------------------------------- | 78 // ----------------------------------------------------------------------------- |
79 // This is an synchronous waiter. The thread is waiting on the given condition | 79 // This is a synchronous waiter. The thread is waiting on the given condition |
80 // variable and the fired flag in this object. | 80 // variable and the fired flag in this object. |
81 // ----------------------------------------------------------------------------- | 81 // ----------------------------------------------------------------------------- |
82 class SyncWaiter : public WaitableEvent::Waiter { | 82 class SyncWaiter : public WaitableEvent::Waiter { |
83 public: | 83 public: |
84 SyncWaiter(ConditionVariable* cv, Lock* lock) | 84 SyncWaiter() |
85 : fired_(false), | 85 : fired_(false), |
86 cv_(cv), | 86 signaling_event_(NULL), |
87 lock_(lock), | 87 lock_(), |
agl
2009/08/19 17:35:35
Isn't this line a no-op?
| |
88 signaling_event_(NULL) { | 88 cv_(&lock_) { |
89 } | 89 } |
90 | 90 |
91 bool Fire(WaitableEvent *signaling_event) { | 91 bool Fire(WaitableEvent* signaling_event) { |
92 lock_->Acquire(); | 92 AutoLock locked(lock_); |
93 const bool previous_value = fired_; | |
94 fired_ = true; | |
95 if (!previous_value) | |
96 signaling_event_ = signaling_event; | |
97 lock_->Release(); | |
98 | 93 |
99 if (previous_value) | 94 if (fired_) |
100 return false; | 95 return false; |
101 | 96 |
102 cv_->Broadcast(); | 97 fired_ = true; |
98 signaling_event_ = signaling_event; | |
103 | 99 |
104 // SyncWaiters are stack allocated on the stack of the blocking thread. | 100 cv_.Broadcast(); |
101 | |
102 // Unlike AsyncWaiter objects, SyncWaiter objects are stack-allocated on | |
103 // the blocking thread's stack. There is no |delete this;| in Fire. The | |
104 // SyncWaiter object is destroyed when it goes out of scope. | |
105 | |
105 return true; | 106 return true; |
106 } | 107 } |
107 | 108 |
108 WaitableEvent* signaled_event() const { | 109 WaitableEvent* signaling_event() const { |
109 return signaling_event_; | 110 return signaling_event_; |
110 } | 111 } |
111 | 112 |
112 // --------------------------------------------------------------------------- | 113 // --------------------------------------------------------------------------- |
113 // These waiters are always stack allocated and don't delete themselves. Thus | 114 // These waiters are always stack allocated and don't delete themselves. Thus |
114 // there's no problem and the ABA tag is the same as the object pointer. | 115 // there's no problem and the ABA tag is the same as the object pointer. |
115 // --------------------------------------------------------------------------- | 116 // --------------------------------------------------------------------------- |
116 bool Compare(void* tag) { | 117 bool Compare(void* tag) { |
117 return this == tag; | 118 return this == tag; |
118 } | 119 } |
119 | 120 |
120 // --------------------------------------------------------------------------- | 121 // --------------------------------------------------------------------------- |
121 // Called with lock held. | 122 // Called with lock held. |
122 // --------------------------------------------------------------------------- | 123 // --------------------------------------------------------------------------- |
123 bool fired() const { | 124 bool fired() const { |
124 return fired_; | 125 return fired_; |
125 } | 126 } |
126 | 127 |
127 // --------------------------------------------------------------------------- | 128 // --------------------------------------------------------------------------- |
128 // During a TimedWait, we need a way to make sure that an auto-reset | 129 // During a TimedWait, we need a way to make sure that an auto-reset |
129 // WaitableEvent doesn't think that this event has been signaled between | 130 // WaitableEvent doesn't think that this event has been signaled between |
130 // unlocking it and removing it from the wait-list. Called with lock held. | 131 // unlocking it and removing it from the wait-list. Called with lock held. |
131 // --------------------------------------------------------------------------- | 132 // --------------------------------------------------------------------------- |
132 void Disable() { | 133 void Disable() { |
133 fired_ = true; | 134 fired_ = true; |
134 } | 135 } |
135 | 136 |
137 Lock* lock() { | |
138 return &lock_; | |
139 } | |
140 | |
141 ConditionVariable* cv() { | |
142 return &cv_; | |
143 } | |
144 | |
136 private: | 145 private: |
137 bool fired_; | 146 bool fired_; |
138 ConditionVariable *const cv_; | |
139 Lock *const lock_; | |
140 WaitableEvent* signaling_event_; // The WaitableEvent which woke us | 147 WaitableEvent* signaling_event_; // The WaitableEvent which woke us |
148 Lock lock_; | |
149 ConditionVariable cv_; | |
141 }; | 150 }; |
142 | 151 |
143 bool WaitableEvent::TimedWait(const TimeDelta& max_time) { | 152 bool WaitableEvent::TimedWait(const TimeDelta& max_time) { |
144 const Time end_time(Time::Now() + max_time); | 153 const Time end_time(Time::Now() + max_time); |
145 const bool finite_time = max_time.ToInternalValue() >= 0; | 154 const bool finite_time = max_time.ToInternalValue() >= 0; |
146 | 155 |
147 kernel_->lock_.Acquire(); | 156 kernel_->lock_.Acquire(); |
148 if (kernel_->signaled_) { | 157 if (kernel_->signaled_) { |
149 if (!kernel_->manual_reset_) { | 158 if (!kernel_->manual_reset_) { |
150 // In this case we were signaled when we had no waiters. Now that | 159 // In this case we were signaled when we had no waiters. Now that |
151 // someone has waited upon us, we can automatically reset. | 160 // someone has waited upon us, we can automatically reset. |
152 kernel_->signaled_ = false; | 161 kernel_->signaled_ = false; |
153 } | 162 } |
154 | 163 |
155 kernel_->lock_.Release(); | 164 kernel_->lock_.Release(); |
156 return true; | 165 return true; |
157 } | 166 } |
158 | 167 |
159 Lock lock; | 168 SyncWaiter sw; |
160 lock.Acquire(); | 169 sw.lock()->Acquire(); |
161 ConditionVariable cv(&lock); | |
162 SyncWaiter sw(&cv, &lock); | |
163 | 170 |
164 Enqueue(&sw); | 171 Enqueue(&sw); |
165 kernel_->lock_.Release(); | 172 kernel_->lock_.Release(); |
166 // We are violating locking order here by holding the SyncWaiter lock but not | 173 // We are violating locking order here by holding the SyncWaiter lock but not |
167 // the WaitableEvent lock. However, this is safe because we don't lock @lock_ | 174 // the WaitableEvent lock. However, this is safe because we don't lock @lock_ |
168 // again before unlocking it. | 175 // again before unlocking it. |
169 | 176 |
170 for (;;) { | 177 for (;;) { |
171 const Time current_time(Time::Now()); | 178 const Time current_time(Time::Now()); |
172 | 179 |
173 if (sw.fired() || (finite_time && current_time >= end_time)) { | 180 if (sw.fired() || (finite_time && current_time >= end_time)) { |
174 const bool return_value = sw.fired(); | 181 const bool return_value = sw.fired(); |
175 | 182 |
176 // We can't acquire @lock_ before releasing @lock (because of locking | 183 // We can't acquire @lock_ before releasing the SyncWaiter lock (because |
177 // order), however, inbetween the two a signal could be fired and @sw | 184 // of locking order), however, in between the two a signal could be fired |
178 // would accept it, however we will still return false, so the signal | 185 // and @sw would accept it, however we will still return false, so the |
179 // would be lost on an auto-reset WaitableEvent. Thus we call Disable | 186 // signal would be lost on an auto-reset WaitableEvent. Thus we call |
180 // which makes sw::Fire return false. | 187 // Disable which makes sw::Fire return false. |
181 sw.Disable(); | 188 sw.Disable(); |
182 lock.Release(); | 189 sw.lock()->Release(); |
183 | 190 |
184 kernel_->lock_.Acquire(); | 191 kernel_->lock_.Acquire(); |
185 kernel_->Dequeue(&sw, &sw); | 192 kernel_->Dequeue(&sw, &sw); |
186 kernel_->lock_.Release(); | 193 kernel_->lock_.Release(); |
187 | 194 |
188 return return_value; | 195 return return_value; |
189 } | 196 } |
190 | 197 |
191 if (finite_time) { | 198 if (finite_time) { |
192 const TimeDelta max_wait(end_time - current_time); | 199 const TimeDelta max_wait(end_time - current_time); |
193 cv.TimedWait(max_wait); | 200 sw.cv()->TimedWait(max_wait); |
194 } else { | 201 } else { |
195 cv.Wait(); | 202 sw.cv()->Wait(); |
196 } | 203 } |
197 } | 204 } |
198 } | 205 } |
199 | 206 |
200 bool WaitableEvent::Wait() { | 207 bool WaitableEvent::Wait() { |
201 return TimedWait(TimeDelta::FromSeconds(-1)); | 208 return TimedWait(TimeDelta::FromSeconds(-1)); |
202 } | 209 } |
203 | 210 |
204 // ----------------------------------------------------------------------------- | 211 // ----------------------------------------------------------------------------- |
205 | 212 |
(...skipping 24 matching lines...) Expand all Loading... | |
230 | 237 |
231 sort(waitables.begin(), waitables.end(), cmp_fst_addr); | 238 sort(waitables.begin(), waitables.end(), cmp_fst_addr); |
232 | 239 |
233 // The set of waitables must be distinct. Since we have just sorted by | 240 // The set of waitables must be distinct. Since we have just sorted by |
234 // address, we can check this cheaply by comparing pairs of consecutive | 241 // address, we can check this cheaply by comparing pairs of consecutive |
235 // elements. | 242 // elements. |
236 for (size_t i = 0; i < waitables.size() - 1; ++i) { | 243 for (size_t i = 0; i < waitables.size() - 1; ++i) { |
237 DCHECK(waitables[i].first != waitables[i+1].first); | 244 DCHECK(waitables[i].first != waitables[i+1].first); |
238 } | 245 } |
239 | 246 |
240 Lock lock; | 247 SyncWaiter sw; |
241 ConditionVariable cv(&lock); | |
242 SyncWaiter sw(&cv, &lock); | |
243 | 248 |
244 const size_t r = EnqueueMany(&waitables[0], count, &sw); | 249 const size_t r = EnqueueMany(&waitables[0], count, &sw); |
245 if (r) { | 250 if (r) { |
246 // One of the events is already signaled. The SyncWaiter has not been | 251 // One of the events is already signaled. The SyncWaiter has not been |
247 // enqueued anywhere. EnqueueMany returns the count of remaining waitables | 252 // enqueued anywhere. EnqueueMany returns the count of remaining waitables |
248 // when the signaled one was seen, so the index of the signaled event is | 253 // when the signaled one was seen, so the index of the signaled event is |
249 // @count - @r. | 254 // @count - @r. |
250 return waitables[count - r].second; | 255 return waitables[count - r].second; |
251 } | 256 } |
252 | 257 |
253 // At this point, we hold the locks on all the WaitableEvents and we have | 258 // At this point, we hold the locks on all the WaitableEvents and we have |
254 // enqueued our waiter in them all. | 259 // enqueued our waiter in them all. |
255 lock.Acquire(); | 260 sw.lock()->Acquire(); |
256 // Release the WaitableEvent locks in the reverse order | 261 // Release the WaitableEvent locks in the reverse order |
257 for (size_t i = 0; i < count; ++i) { | 262 for (size_t i = 0; i < count; ++i) { |
258 waitables[count - (1 + i)].first->kernel_->lock_.Release(); | 263 waitables[count - (1 + i)].first->kernel_->lock_.Release(); |
259 } | 264 } |
260 | 265 |
261 for (;;) { | 266 for (;;) { |
262 if (sw.fired()) | 267 if (sw.fired()) |
263 break; | 268 break; |
264 | 269 |
265 cv.Wait(); | 270 sw.cv()->Wait(); |
266 } | 271 } |
267 lock.Release(); | 272 sw.lock()->Release(); |
268 | 273 |
269 // The address of the WaitableEvent which fired is stored in the SyncWaiter. | 274 // The address of the WaitableEvent which fired is stored in the SyncWaiter. |
270 WaitableEvent *const signaled_event = sw.signaled_event(); | 275 WaitableEvent *const signaled_event = sw.signaling_event(); |
271 // This will store the index of the raw_waitables which fired. | 276 // This will store the index of the raw_waitables which fired. |
272 size_t signaled_index = 0; | 277 size_t signaled_index = 0; |
273 | 278 |
274 // Take the locks of each WaitableEvent in turn (except the signaled one) and | 279 // Take the locks of each WaitableEvent in turn (except the signaled one) and |
275 // remove our SyncWaiter from the wait-list | 280 // remove our SyncWaiter from the wait-list |
276 for (size_t i = 0; i < count; ++i) { | 281 for (size_t i = 0; i < count; ++i) { |
277 if (raw_waitables[i] != signaled_event) { | 282 if (raw_waitables[i] != signaled_event) { |
278 raw_waitables[i]->kernel_->lock_.Acquire(); | 283 raw_waitables[i]->kernel_->lock_.Acquire(); |
279 // There's no possible ABA issue with the address of the SyncWaiter here | 284 // There's no possible ABA issue with the address of the SyncWaiter here |
280 // because it lives on the stack. Thus the tag value is just the pointer | 285 // because it lives on the stack. Thus the tag value is just the pointer |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
381 return true; | 386 return true; |
382 } | 387 } |
383 } | 388 } |
384 | 389 |
385 return false; | 390 return false; |
386 } | 391 } |
387 | 392 |
388 // ----------------------------------------------------------------------------- | 393 // ----------------------------------------------------------------------------- |
389 | 394 |
390 } // namespace base | 395 } // namespace base |
OLD | NEW |