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 17 matching lines...) Expand all Loading... |
28 // firing a waiter and so we can store that pointer to find out which event | 28 // firing a waiter and so we can store that pointer to find out which event |
29 // triggered. | 29 // triggered. |
30 // ----------------------------------------------------------------------------- | 30 // ----------------------------------------------------------------------------- |
31 | 31 |
32 namespace base { | 32 namespace base { |
33 | 33 |
34 // ----------------------------------------------------------------------------- | 34 // ----------------------------------------------------------------------------- |
35 // This is just an abstract base class for waking the two types of waiters | 35 // This is just an abstract base class for waking the two types of waiters |
36 // ----------------------------------------------------------------------------- | 36 // ----------------------------------------------------------------------------- |
37 WaitableEvent::WaitableEvent(bool manual_reset, bool initially_signaled) | 37 WaitableEvent::WaitableEvent(bool manual_reset, bool initially_signaled) |
38 : signaled_(initially_signaled), | 38 : kernel_(new WaitableEventKernel(manual_reset, initially_signaled)) { |
39 manual_reset_(manual_reset) { | |
40 } | 39 } |
41 | 40 |
42 WaitableEvent::~WaitableEvent() { | 41 WaitableEvent::~WaitableEvent() { |
43 if (!waiters_.empty()) { | |
44 LOG(ERROR) << "Destroying a WaitableEvent (" << this << ") with " | |
45 << waiters_.size() << " waiters"; | |
46 NOTREACHED() << "Aborting."; | |
47 } | |
48 } | 42 } |
49 | 43 |
50 void WaitableEvent::Reset() { | 44 void WaitableEvent::Reset() { |
51 AutoLock locked(lock_); | 45 AutoLock locked(kernel_->lock_); |
52 signaled_ = false; | 46 kernel_->signaled_ = false; |
53 } | 47 } |
54 | 48 |
55 void WaitableEvent::Signal() { | 49 void WaitableEvent::Signal() { |
56 AutoLock locked(lock_); | 50 AutoLock locked(kernel_->lock_); |
57 | 51 |
58 if (signaled_) | 52 if (kernel_->signaled_) |
59 return; | 53 return; |
60 | 54 |
61 if (manual_reset_) { | 55 if (kernel_->manual_reset_) { |
62 SignalAll(); | 56 SignalAll(); |
63 signaled_ = true; | 57 kernel_->signaled_ = true; |
64 } else { | 58 } else { |
65 // In the case of auto reset, if no waiters were woken, we remain | 59 // In the case of auto reset, if no waiters were woken, we remain |
66 // signaled. | 60 // signaled. |
67 if (!SignalOne()) | 61 if (!SignalOne()) |
68 signaled_ = true; | 62 kernel_->signaled_ = true; |
69 } | 63 } |
70 } | 64 } |
71 | 65 |
72 bool WaitableEvent::IsSignaled() { | 66 bool WaitableEvent::IsSignaled() { |
73 AutoLock locked(lock_); | 67 AutoLock locked(kernel_->lock_); |
74 | 68 |
75 const bool result = signaled_; | 69 const bool result = kernel_->signaled_; |
76 if (result && !manual_reset_) | 70 if (result && !kernel_->manual_reset_) |
77 signaled_ = false; | 71 kernel_->signaled_ = false; |
78 return result; | 72 return result; |
79 } | 73 } |
80 | 74 |
81 // ----------------------------------------------------------------------------- | 75 // ----------------------------------------------------------------------------- |
82 // Synchronous waits | 76 // Synchronous waits |
83 | 77 |
84 // ----------------------------------------------------------------------------- | 78 // ----------------------------------------------------------------------------- |
85 // This is an synchronous waiter. The thread is waiting on the given condition | 79 // This is an synchronous waiter. The thread is waiting on the given condition |
86 // variable and the fired flag in this object. | 80 // variable and the fired flag in this object. |
87 // ----------------------------------------------------------------------------- | 81 // ----------------------------------------------------------------------------- |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
143 bool fired_; | 137 bool fired_; |
144 ConditionVariable *const cv_; | 138 ConditionVariable *const cv_; |
145 Lock *const lock_; | 139 Lock *const lock_; |
146 WaitableEvent* signaling_event_; // The WaitableEvent which woke us | 140 WaitableEvent* signaling_event_; // The WaitableEvent which woke us |
147 }; | 141 }; |
148 | 142 |
149 bool WaitableEvent::TimedWait(const TimeDelta& max_time) { | 143 bool WaitableEvent::TimedWait(const TimeDelta& max_time) { |
150 const Time end_time(Time::Now() + max_time); | 144 const Time end_time(Time::Now() + max_time); |
151 const bool finite_time = max_time.ToInternalValue() >= 0; | 145 const bool finite_time = max_time.ToInternalValue() >= 0; |
152 | 146 |
153 lock_.Acquire(); | 147 kernel_->lock_.Acquire(); |
154 if (signaled_) { | 148 if (kernel_->signaled_) { |
155 if (!manual_reset_) { | 149 if (!kernel_->manual_reset_) { |
156 // In this case we were signaled when we had no waiters. Now that | 150 // In this case we were signaled when we had no waiters. Now that |
157 // someone has waited upon us, we can automatically reset. | 151 // someone has waited upon us, we can automatically reset. |
158 signaled_ = false; | 152 kernel_->signaled_ = false; |
159 } | 153 } |
160 | 154 |
161 lock_.Release(); | 155 kernel_->lock_.Release(); |
162 return true; | 156 return true; |
163 } | 157 } |
164 | 158 |
165 Lock lock; | 159 Lock lock; |
166 lock.Acquire(); | 160 lock.Acquire(); |
167 ConditionVariable cv(&lock); | 161 ConditionVariable cv(&lock); |
168 SyncWaiter sw(&cv, &lock); | 162 SyncWaiter sw(&cv, &lock); |
169 | 163 |
170 Enqueue(&sw); | 164 Enqueue(&sw); |
171 lock_.Release(); | 165 kernel_->lock_.Release(); |
172 // We are violating locking order here by holding the SyncWaiter lock but not | 166 // We are violating locking order here by holding the SyncWaiter lock but not |
173 // the WaitableEvent lock. However, this is safe because we don't lock @lock_ | 167 // the WaitableEvent lock. However, this is safe because we don't lock @lock_ |
174 // again before unlocking it. | 168 // again before unlocking it. |
175 | 169 |
176 for (;;) { | 170 for (;;) { |
177 const Time current_time(Time::Now()); | 171 const Time current_time(Time::Now()); |
178 | 172 |
179 if (sw.fired() || (finite_time && current_time >= end_time)) { | 173 if (sw.fired() || (finite_time && current_time >= end_time)) { |
180 const bool return_value = sw.fired(); | 174 const bool return_value = sw.fired(); |
181 | 175 |
182 // We can't acquire @lock_ before releasing @lock (because of locking | 176 // We can't acquire @lock_ before releasing @lock (because of locking |
183 // order), however, inbetween the two a signal could be fired and @sw | 177 // order), however, inbetween the two a signal could be fired and @sw |
184 // would accept it, however we will still return false, so the signal | 178 // would accept it, however we will still return false, so the signal |
185 // would be lost on an auto-reset WaitableEvent. Thus we call Disable | 179 // would be lost on an auto-reset WaitableEvent. Thus we call Disable |
186 // which makes sw::Fire return false. | 180 // which makes sw::Fire return false. |
187 sw.Disable(); | 181 sw.Disable(); |
188 lock.Release(); | 182 lock.Release(); |
189 | 183 |
190 lock_.Acquire(); | 184 kernel_->lock_.Acquire(); |
191 Dequeue(&sw, &sw); | 185 kernel_->Dequeue(&sw, &sw); |
192 lock_.Release(); | 186 kernel_->lock_.Release(); |
193 | 187 |
194 return return_value; | 188 return return_value; |
195 } | 189 } |
196 | 190 |
197 if (finite_time) { | 191 if (finite_time) { |
198 const TimeDelta max_wait(end_time - current_time); | 192 const TimeDelta max_wait(end_time - current_time); |
199 cv.TimedWait(max_wait); | 193 cv.TimedWait(max_wait); |
200 } else { | 194 } else { |
201 cv.Wait(); | 195 cv.Wait(); |
202 } | 196 } |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
254 // when the signaled one was seen, so the index of the signaled event is | 248 // when the signaled one was seen, so the index of the signaled event is |
255 // @count - @r. | 249 // @count - @r. |
256 return waitables[count - r].second; | 250 return waitables[count - r].second; |
257 } | 251 } |
258 | 252 |
259 // At this point, we hold the locks on all the WaitableEvents and we have | 253 // At this point, we hold the locks on all the WaitableEvents and we have |
260 // enqueued our waiter in them all. | 254 // enqueued our waiter in them all. |
261 lock.Acquire(); | 255 lock.Acquire(); |
262 // Release the WaitableEvent locks in the reverse order | 256 // Release the WaitableEvent locks in the reverse order |
263 for (size_t i = 0; i < count; ++i) { | 257 for (size_t i = 0; i < count; ++i) { |
264 waitables[count - (1 + i)].first->lock_.Release(); | 258 waitables[count - (1 + i)].first->kernel_->lock_.Release(); |
265 } | 259 } |
266 | 260 |
267 for (;;) { | 261 for (;;) { |
268 if (sw.fired()) | 262 if (sw.fired()) |
269 break; | 263 break; |
270 | 264 |
271 cv.Wait(); | 265 cv.Wait(); |
272 } | 266 } |
273 lock.Release(); | 267 lock.Release(); |
274 | 268 |
275 // The address of the WaitableEvent which fired is stored in the SyncWaiter. | 269 // The address of the WaitableEvent which fired is stored in the SyncWaiter. |
276 WaitableEvent *const signaled_event = sw.signaled_event(); | 270 WaitableEvent *const signaled_event = sw.signaled_event(); |
277 // This will store the index of the raw_waitables which fired. | 271 // This will store the index of the raw_waitables which fired. |
278 size_t signaled_index = 0; | 272 size_t signaled_index = 0; |
279 | 273 |
280 // Take the locks of each WaitableEvent in turn (except the signaled one) and | 274 // Take the locks of each WaitableEvent in turn (except the signaled one) and |
281 // remove our SyncWaiter from the wait-list | 275 // remove our SyncWaiter from the wait-list |
282 for (size_t i = 0; i < count; ++i) { | 276 for (size_t i = 0; i < count; ++i) { |
283 if (raw_waitables[i] != signaled_event) { | 277 if (raw_waitables[i] != signaled_event) { |
284 raw_waitables[i]->lock_.Acquire(); | 278 raw_waitables[i]->kernel_->lock_.Acquire(); |
285 // There's no possible ABA issue with the address of the SyncWaiter here | 279 // There's no possible ABA issue with the address of the SyncWaiter here |
286 // because it lives on the stack. Thus the tag value is just the pointer | 280 // because it lives on the stack. Thus the tag value is just the pointer |
287 // value again. | 281 // value again. |
288 raw_waitables[i]->Dequeue(&sw, &sw); | 282 raw_waitables[i]->kernel_->Dequeue(&sw, &sw); |
289 raw_waitables[i]->lock_.Release(); | 283 raw_waitables[i]->kernel_->lock_.Release(); |
290 } else { | 284 } else { |
291 signaled_index = i; | 285 signaled_index = i; |
292 } | 286 } |
293 } | 287 } |
294 | 288 |
295 return signaled_index; | 289 return signaled_index; |
296 } | 290 } |
297 | 291 |
298 // ----------------------------------------------------------------------------- | 292 // ----------------------------------------------------------------------------- |
299 // If return value == 0: | 293 // If return value == 0: |
300 // The locks of the WaitableEvents have been taken in order and the Waiter has | 294 // The locks of the WaitableEvents have been taken in order and the Waiter has |
301 // been enqueued in the wait-list of each. None of the WaitableEvents are | 295 // been enqueued in the wait-list of each. None of the WaitableEvents are |
302 // currently signaled | 296 // currently signaled |
303 // else: | 297 // else: |
304 // None of the WaitableEvent locks are held. The Waiter has not been enqueued | 298 // None of the WaitableEvent locks are held. The Waiter has not been enqueued |
305 // in any of them and the return value is the index of the first WaitableEvent | 299 // in any of them and the return value is the index of the first WaitableEvent |
306 // which was signaled, from the end of the array. | 300 // which was signaled, from the end of the array. |
307 // ----------------------------------------------------------------------------- | 301 // ----------------------------------------------------------------------------- |
308 // static | 302 // static |
309 size_t WaitableEvent::EnqueueMany | 303 size_t WaitableEvent::EnqueueMany |
310 (std::pair<WaitableEvent*, size_t>* waitables, | 304 (std::pair<WaitableEvent*, size_t>* waitables, |
311 size_t count, Waiter* waiter) { | 305 size_t count, Waiter* waiter) { |
312 if (!count) | 306 if (!count) |
313 return 0; | 307 return 0; |
314 | 308 |
315 waitables[0].first->lock_.Acquire(); | 309 waitables[0].first->kernel_->lock_.Acquire(); |
316 if (waitables[0].first->signaled_) { | 310 if (waitables[0].first->kernel_->signaled_) { |
317 if (!waitables[0].first->manual_reset_) | 311 if (!waitables[0].first->kernel_->manual_reset_) |
318 waitables[0].first->signaled_ = false; | 312 waitables[0].first->kernel_->signaled_ = false; |
319 waitables[0].first->lock_.Release(); | 313 waitables[0].first->kernel_->lock_.Release(); |
320 return count; | 314 return count; |
321 } | 315 } |
322 | 316 |
323 const size_t r = EnqueueMany(waitables + 1, count - 1, waiter); | 317 const size_t r = EnqueueMany(waitables + 1, count - 1, waiter); |
324 if (r) { | 318 if (r) { |
325 waitables[0].first->lock_.Release(); | 319 waitables[0].first->kernel_->lock_.Release(); |
326 } else { | 320 } else { |
327 waitables[0].first->Enqueue(waiter); | 321 waitables[0].first->Enqueue(waiter); |
328 } | 322 } |
329 | 323 |
330 return r; | 324 return r; |
331 } | 325 } |
332 | 326 |
333 // ----------------------------------------------------------------------------- | 327 // ----------------------------------------------------------------------------- |
334 | 328 |
335 | 329 |
336 // ----------------------------------------------------------------------------- | 330 // ----------------------------------------------------------------------------- |
337 // Private functions... | 331 // Private functions... |
338 | 332 |
339 // ----------------------------------------------------------------------------- | 333 // ----------------------------------------------------------------------------- |
340 // Wake all waiting waiters. Called with lock held. | 334 // Wake all waiting waiters. Called with lock held. |
341 // ----------------------------------------------------------------------------- | 335 // ----------------------------------------------------------------------------- |
342 bool WaitableEvent::SignalAll() { | 336 bool WaitableEvent::SignalAll() { |
343 bool signaled_at_least_one = false; | 337 bool signaled_at_least_one = false; |
344 | 338 |
345 for (std::list<Waiter*>::iterator | 339 for (std::list<Waiter*>::iterator |
346 i = waiters_.begin(); i != waiters_.end(); ++i) { | 340 i = kernel_->waiters_.begin(); i != kernel_->waiters_.end(); ++i) { |
347 if ((*i)->Fire(this)) | 341 if ((*i)->Fire(this)) |
348 signaled_at_least_one = true; | 342 signaled_at_least_one = true; |
349 } | 343 } |
350 | 344 |
351 waiters_.clear(); | 345 kernel_->waiters_.clear(); |
352 return signaled_at_least_one; | 346 return signaled_at_least_one; |
353 } | 347 } |
354 | 348 |
355 // --------------------------------------------------------------------------- | 349 // --------------------------------------------------------------------------- |
356 // Try to wake a single waiter. Return true if one was woken. Called with lock | 350 // Try to wake a single waiter. Return true if one was woken. Called with lock |
357 // held. | 351 // held. |
358 // --------------------------------------------------------------------------- | 352 // --------------------------------------------------------------------------- |
359 bool WaitableEvent::SignalOne() { | 353 bool WaitableEvent::SignalOne() { |
360 for (;;) { | 354 for (;;) { |
361 if (waiters_.empty()) | 355 if (kernel_->waiters_.empty()) |
362 return false; | 356 return false; |
363 | 357 |
364 const bool r = (*waiters_.begin())->Fire(this); | 358 const bool r = (*kernel_->waiters_.begin())->Fire(this); |
365 waiters_.pop_front(); | 359 kernel_->waiters_.pop_front(); |
366 if (r) | 360 if (r) |
367 return true; | 361 return true; |
368 } | 362 } |
369 } | 363 } |
370 | 364 |
371 // ----------------------------------------------------------------------------- | 365 // ----------------------------------------------------------------------------- |
372 // Add a waiter to the list of those waiting. Called with lock held. | 366 // Add a waiter to the list of those waiting. Called with lock held. |
373 // ----------------------------------------------------------------------------- | 367 // ----------------------------------------------------------------------------- |
374 void WaitableEvent::Enqueue(Waiter* waiter) { | 368 void WaitableEvent::Enqueue(Waiter* waiter) { |
375 waiters_.push_back(waiter); | 369 kernel_->waiters_.push_back(waiter); |
376 } | 370 } |
377 | 371 |
378 // ----------------------------------------------------------------------------- | 372 // ----------------------------------------------------------------------------- |
379 // Remove a waiter from the list of those waiting. Return true if the waiter was | 373 // Remove a waiter from the list of those waiting. Return true if the waiter was |
380 // actually removed. Called with lock held. | 374 // actually removed. Called with lock held. |
381 // ----------------------------------------------------------------------------- | 375 // ----------------------------------------------------------------------------- |
382 bool WaitableEvent::Dequeue(Waiter* waiter, void* tag) { | 376 bool WaitableEvent::WaitableEventKernel::Dequeue(Waiter* waiter, void* tag) { |
383 for (std::list<Waiter*>::iterator | 377 for (std::list<Waiter*>::iterator |
384 i = waiters_.begin(); i != waiters_.end(); ++i) { | 378 i = waiters_.begin(); i != waiters_.end(); ++i) { |
385 if (*i == waiter && (*i)->Compare(tag)) { | 379 if (*i == waiter && (*i)->Compare(tag)) { |
386 waiters_.erase(i); | 380 waiters_.erase(i); |
387 return true; | 381 return true; |
388 } | 382 } |
389 } | 383 } |
390 | 384 |
391 return false; | 385 return false; |
392 } | 386 } |
393 | 387 |
394 // ----------------------------------------------------------------------------- | 388 // ----------------------------------------------------------------------------- |
395 | 389 |
396 } // namespace base | 390 } // namespace base |
OLD | NEW |