| 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 |