Chromium Code Reviews| 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 |