Chromium Code Reviews| 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/condition_variable.h" | 5 #include "base/synchronization/condition_variable.h" |
| 6 | 6 |
| 7 #include <windows.h> | |
| 7 #include <stack> | 8 #include <stack> |
| 8 | 9 |
| 10 #include "base/compiler_specific.h" | |
| 9 #include "base/logging.h" | 11 #include "base/logging.h" |
| 10 #include "base/synchronization/lock.h" | 12 #include "base/synchronization/lock.h" |
| 11 #include "base/time.h" | 13 #include "base/time.h" |
| 12 | 14 |
| 13 namespace base { | 15 namespace base { |
| 16 // Abstract class of the pimpl, idiom. TODO(cpu): create the | |
| 17 // WinVistaCondVar once the WinXPCondVar lands. | |
| 18 class ConditionVarImpl { | |
| 19 public: | |
| 20 virtual ~ConditionVarImpl() {}; | |
| 21 virtual void Wait() = 0; | |
| 22 virtual void TimedWait(const TimeDelta& max_time) = 0; | |
| 23 virtual void Broadcast() = 0; | |
| 24 virtual void Signal() = 0; | |
| 25 }; | |
| 14 | 26 |
| 15 ConditionVariable::ConditionVariable(Lock* user_lock) | 27 class WinXPCondVar : public ConditionVarImpl { |
| 28 public: | |
| 29 WinXPCondVar(Lock* user_lock); | |
| 30 ~WinXPCondVar(); | |
| 31 // Overridden from ConditionVarImpl. | |
|
brettw
2011/12/06 23:44:54
Can you put a blank line above this?
| |
| 32 virtual void Wait() OVERRIDE; | |
| 33 virtual void TimedWait(const TimeDelta& max_time) OVERRIDE; | |
| 34 virtual void Broadcast() OVERRIDE; | |
| 35 virtual void Signal() OVERRIDE; | |
| 36 | |
| 37 // Define Event class that is used to form circularly linked lists. | |
| 38 // The list container is an element with NULL as its handle_ value. | |
| 39 // The actual list elements have a non-zero handle_ value. | |
| 40 // All calls to methods MUST be done under protection of a lock so that links | |
| 41 // can be validated. Without the lock, some links might asynchronously | |
| 42 // change, and the assertions would fail (as would list change operations). | |
| 43 class Event { | |
| 44 public: | |
| 45 // Default constructor with no arguments creates a list container. | |
| 46 Event(); | |
| 47 ~Event(); | |
| 48 | |
| 49 // InitListElement transitions an instance from a container, to an element. | |
| 50 void InitListElement(); | |
| 51 | |
| 52 // Methods for use on lists. | |
| 53 bool IsEmpty() const; | |
| 54 void PushBack(Event* other); | |
| 55 Event* PopFront(); | |
| 56 Event* PopBack(); | |
| 57 | |
| 58 // Methods for use on list elements. | |
| 59 // Accessor method. | |
| 60 HANDLE handle() const; | |
| 61 // Pull an element from a list (if it's in one). | |
| 62 Event* Extract(); | |
| 63 | |
| 64 // Method for use on a list element or on a list. | |
| 65 bool IsSingleton() const; | |
| 66 | |
| 67 private: | |
| 68 // Provide pre/post conditions to validate correct manipulations. | |
| 69 bool ValidateAsDistinct(Event* other) const; | |
| 70 bool ValidateAsItem() const; | |
| 71 bool ValidateAsList() const; | |
| 72 bool ValidateLinks() const; | |
| 73 | |
| 74 HANDLE handle_; | |
| 75 Event* next_; | |
| 76 Event* prev_; | |
| 77 DISALLOW_COPY_AND_ASSIGN(Event); | |
| 78 }; | |
| 79 | |
| 80 // Note that RUNNING is an unlikely number to have in RAM by accident. | |
| 81 // This helps with defensive destructor coding in the face of user error. | |
| 82 enum RunState { SHUTDOWN = 0, RUNNING = 64213 }; | |
| 83 | |
| 84 // Internal implementation methods supporting Wait(). | |
| 85 Event* GetEventForWaiting(); | |
| 86 void RecycleEvent(Event* used_event); | |
| 87 | |
| 88 RunState run_state_; | |
| 89 | |
| 90 // Private critical section for access to member data. | |
| 91 base::Lock internal_lock_; | |
| 92 | |
| 93 // Lock that is acquired before calling Wait(). | |
| 94 base::Lock& user_lock_; | |
| 95 | |
| 96 // Events that threads are blocked on. | |
| 97 Event waiting_list_; | |
| 98 | |
| 99 // Free list for old events. | |
| 100 Event recycling_list_; | |
| 101 int recycling_list_size_; | |
| 102 | |
| 103 // The number of allocated, but not yet deleted events. | |
| 104 int allocation_counter_; | |
| 105 }; | |
| 106 | |
| 107 WinXPCondVar::WinXPCondVar(Lock* user_lock) | |
| 16 : user_lock_(*user_lock), | 108 : user_lock_(*user_lock), |
| 17 run_state_(RUNNING), | 109 run_state_(RUNNING), |
| 18 allocation_counter_(0), | 110 allocation_counter_(0), |
| 19 recycling_list_size_(0) { | 111 recycling_list_size_(0) { |
| 20 DCHECK(user_lock); | 112 DCHECK(user_lock); |
| 21 } | 113 } |
| 22 | 114 |
| 23 ConditionVariable::~ConditionVariable() { | 115 WinXPCondVar::~WinXPCondVar() { |
| 24 AutoLock auto_lock(internal_lock_); | 116 AutoLock auto_lock(internal_lock_); |
| 25 run_state_ = SHUTDOWN; // Prevent any more waiting. | 117 run_state_ = SHUTDOWN; // Prevent any more waiting. |
| 26 | 118 |
| 27 DCHECK_EQ(recycling_list_size_, allocation_counter_); | 119 DCHECK_EQ(recycling_list_size_, allocation_counter_); |
| 28 if (recycling_list_size_ != allocation_counter_) { // Rare shutdown problem. | 120 if (recycling_list_size_ != allocation_counter_) { // Rare shutdown problem. |
| 29 // There are threads of execution still in this->TimedWait() and yet the | 121 // There are threads of execution still in this->TimedWait() and yet the |
| 30 // caller has instigated the destruction of this instance :-/. | 122 // caller has instigated the destruction of this instance :-/. |
| 31 // A common reason for such "overly hasty" destruction is that the caller | 123 // A common reason for such "overly hasty" destruction is that the caller |
| 32 // was not willing to wait for all the threads to terminate. Such hasty | 124 // was not willing to wait for all the threads to terminate. Such hasty |
| 33 // actions are a violation of our usage contract, but we'll give the | 125 // actions are a violation of our usage contract, but we'll give the |
| 34 // waiting thread(s) one last chance to exit gracefully (prior to our | 126 // waiting thread(s) one last chance to exit gracefully (prior to our |
| 35 // destruction). | 127 // destruction). |
| 36 // Note: waiting_list_ *might* be empty, but recycling is still pending. | 128 // Note: waiting_list_ *might* be empty, but recycling is still pending. |
| 37 AutoUnlock auto_unlock(internal_lock_); | 129 AutoUnlock auto_unlock(internal_lock_); |
| 38 Broadcast(); // Make sure all waiting threads have been signaled. | 130 Broadcast(); // Make sure all waiting threads have been signaled. |
| 39 Sleep(10); // Give threads a chance to grab internal_lock_. | 131 Sleep(10); // Give threads a chance to grab internal_lock_. |
| 40 // All contained threads should be blocked on user_lock_ by now :-). | 132 // All contained threads should be blocked on user_lock_ by now :-). |
| 41 } // Reacquire internal_lock_. | 133 } // Reacquire internal_lock_. |
| 42 | 134 |
| 43 DCHECK_EQ(recycling_list_size_, allocation_counter_); | 135 DCHECK_EQ(recycling_list_size_, allocation_counter_); |
| 44 } | 136 } |
| 45 | 137 |
| 46 void ConditionVariable::Wait() { | 138 void WinXPCondVar::Wait() { |
| 47 // Default to "wait forever" timing, which means have to get a Signal() | 139 // Default to "wait forever" timing, which means have to get a Signal() |
| 48 // or Broadcast() to come out of this wait state. | 140 // or Broadcast() to come out of this wait state. |
| 49 TimedWait(TimeDelta::FromMilliseconds(INFINITE)); | 141 TimedWait(TimeDelta::FromMilliseconds(INFINITE)); |
| 50 } | 142 } |
| 51 | 143 |
| 52 void ConditionVariable::TimedWait(const TimeDelta& max_time) { | 144 void WinXPCondVar::TimedWait(const TimeDelta& max_time) { |
| 53 Event* waiting_event; | 145 Event* waiting_event; |
| 54 HANDLE handle; | 146 HANDLE handle; |
| 55 { | 147 { |
| 56 AutoLock auto_lock(internal_lock_); | 148 AutoLock auto_lock(internal_lock_); |
| 57 if (RUNNING != run_state_) return; // Destruction in progress. | 149 if (RUNNING != run_state_) return; // Destruction in progress. |
| 58 waiting_event = GetEventForWaiting(); | 150 waiting_event = GetEventForWaiting(); |
| 59 handle = waiting_event->handle(); | 151 handle = waiting_event->handle(); |
| 60 DCHECK(handle); | 152 DCHECK(handle); |
| 61 } // Release internal_lock. | 153 } // Release internal_lock. |
| 62 | 154 |
| 63 { | 155 { |
| 64 AutoUnlock unlock(user_lock_); // Release caller's lock | 156 AutoUnlock unlock(user_lock_); // Release caller's lock |
| 65 WaitForSingleObject(handle, static_cast<DWORD>(max_time.InMilliseconds())); | 157 WaitForSingleObject(handle, static_cast<DWORD>(max_time.InMilliseconds())); |
| 66 // Minimize spurious signal creation window by recycling asap. | 158 // Minimize spurious signal creation window by recycling asap. |
| 67 AutoLock auto_lock(internal_lock_); | 159 AutoLock auto_lock(internal_lock_); |
| 68 RecycleEvent(waiting_event); | 160 RecycleEvent(waiting_event); |
| 69 // Release internal_lock_ | 161 // Release internal_lock_ |
| 70 } // Reacquire callers lock to depth at entry. | 162 } // Reacquire callers lock to depth at entry. |
| 71 } | 163 } |
| 72 | 164 |
| 73 // Broadcast() is guaranteed to signal all threads that were waiting (i.e., had | 165 // Broadcast() is guaranteed to signal all threads that were waiting (i.e., had |
| 74 // a cv_event internally allocated for them) before Broadcast() was called. | 166 // a cv_event internally allocated for them) before Broadcast() was called. |
| 75 void ConditionVariable::Broadcast() { | 167 void WinXPCondVar::Broadcast() { |
| 76 std::stack<HANDLE> handles; // See FAQ-question-10. | 168 std::stack<HANDLE> handles; // See FAQ-question-10. |
| 77 { | 169 { |
| 78 AutoLock auto_lock(internal_lock_); | 170 AutoLock auto_lock(internal_lock_); |
| 79 if (waiting_list_.IsEmpty()) | 171 if (waiting_list_.IsEmpty()) |
| 80 return; | 172 return; |
| 81 while (!waiting_list_.IsEmpty()) | 173 while (!waiting_list_.IsEmpty()) |
| 82 // This is not a leak from waiting_list_. See FAQ-question 12. | 174 // This is not a leak from waiting_list_. See FAQ-question 12. |
| 83 handles.push(waiting_list_.PopBack()->handle()); | 175 handles.push(waiting_list_.PopBack()->handle()); |
| 84 } // Release internal_lock_. | 176 } // Release internal_lock_. |
| 85 while (!handles.empty()) { | 177 while (!handles.empty()) { |
| 86 SetEvent(handles.top()); | 178 SetEvent(handles.top()); |
| 87 handles.pop(); | 179 handles.pop(); |
| 88 } | 180 } |
| 89 } | 181 } |
| 90 | 182 |
| 91 // Signal() will select one of the waiting threads, and signal it (signal its | 183 // Signal() will select one of the waiting threads, and signal it (signal its |
| 92 // cv_event). For better performance we signal the thread that went to sleep | 184 // cv_event). For better performance we signal the thread that went to sleep |
| 93 // most recently (LIFO). If we want fairness, then we wake the thread that has | 185 // most recently (LIFO). If we want fairness, then we wake the thread that has |
| 94 // been sleeping the longest (FIFO). | 186 // been sleeping the longest (FIFO). |
| 95 void ConditionVariable::Signal() { | 187 void WinXPCondVar::Signal() { |
| 96 HANDLE handle; | 188 HANDLE handle; |
| 97 { | 189 { |
| 98 AutoLock auto_lock(internal_lock_); | 190 AutoLock auto_lock(internal_lock_); |
| 99 if (waiting_list_.IsEmpty()) | 191 if (waiting_list_.IsEmpty()) |
| 100 return; // No one to signal. | 192 return; // No one to signal. |
| 101 // Only performance option should be used. | 193 // Only performance option should be used. |
| 102 // This is not a leak from waiting_list. See FAQ-question 12. | 194 // This is not a leak from waiting_list. See FAQ-question 12. |
| 103 handle = waiting_list_.PopBack()->handle(); // LIFO. | 195 handle = waiting_list_.PopBack()->handle(); // LIFO. |
| 104 } // Release internal_lock_. | 196 } // Release internal_lock_. |
| 105 SetEvent(handle); | 197 SetEvent(handle); |
| 106 } | 198 } |
| 107 | 199 |
| 108 // GetEventForWaiting() provides a unique cv_event for any caller that needs to | 200 // GetEventForWaiting() provides a unique cv_event for any caller that needs to |
| 109 // wait. This means that (worst case) we may over time create as many cv_event | 201 // wait. This means that (worst case) we may over time create as many cv_event |
| 110 // objects as there are threads simultaneously using this instance's Wait() | 202 // objects as there are threads simultaneously using this instance's Wait() |
| 111 // functionality. | 203 // functionality. |
| 112 ConditionVariable::Event* ConditionVariable::GetEventForWaiting() { | 204 WinXPCondVar::Event* WinXPCondVar::GetEventForWaiting() { |
| 113 // We hold internal_lock, courtesy of Wait(). | 205 // We hold internal_lock, courtesy of Wait(). |
| 114 Event* cv_event; | 206 Event* cv_event; |
| 115 if (0 == recycling_list_size_) { | 207 if (0 == recycling_list_size_) { |
| 116 DCHECK(recycling_list_.IsEmpty()); | 208 DCHECK(recycling_list_.IsEmpty()); |
| 117 cv_event = new Event(); | 209 cv_event = new Event(); |
| 118 cv_event->InitListElement(); | 210 cv_event->InitListElement(); |
| 119 allocation_counter_++; | 211 allocation_counter_++; |
| 120 DCHECK(cv_event->handle()); | 212 DCHECK(cv_event->handle()); |
| 121 } else { | 213 } else { |
| 122 cv_event = recycling_list_.PopFront(); | 214 cv_event = recycling_list_.PopFront(); |
| 123 recycling_list_size_--; | 215 recycling_list_size_--; |
| 124 } | 216 } |
| 125 waiting_list_.PushBack(cv_event); | 217 waiting_list_.PushBack(cv_event); |
| 126 return cv_event; | 218 return cv_event; |
| 127 } | 219 } |
| 128 | 220 |
| 129 // RecycleEvent() takes a cv_event that was previously used for Wait()ing, and | 221 // RecycleEvent() takes a cv_event that was previously used for Wait()ing, and |
| 130 // recycles it for use in future Wait() calls for this or other threads. | 222 // recycles it for use in future Wait() calls for this or other threads. |
| 131 // Note that there is a tiny chance that the cv_event is still signaled when we | 223 // Note that there is a tiny chance that the cv_event is still signaled when we |
| 132 // obtain it, and that can cause spurious signals (if/when we re-use the | 224 // obtain it, and that can cause spurious signals (if/when we re-use the |
| 133 // cv_event), but such is quite rare (see FAQ-question-5). | 225 // cv_event), but such is quite rare (see FAQ-question-5). |
| 134 void ConditionVariable::RecycleEvent(Event* used_event) { | 226 void WinXPCondVar::RecycleEvent(Event* used_event) { |
| 135 // We hold internal_lock, courtesy of Wait(). | 227 // We hold internal_lock, courtesy of Wait(). |
| 136 // If the cv_event timed out, then it is necessary to remove it from | 228 // If the cv_event timed out, then it is necessary to remove it from |
| 137 // waiting_list_. If it was selected by Broadcast() or Signal(), then it is | 229 // waiting_list_. If it was selected by Broadcast() or Signal(), then it is |
| 138 // already gone. | 230 // already gone. |
| 139 used_event->Extract(); // Possibly redundant | 231 used_event->Extract(); // Possibly redundant |
| 140 recycling_list_.PushBack(used_event); | 232 recycling_list_.PushBack(used_event); |
| 141 recycling_list_size_++; | 233 recycling_list_size_++; |
| 142 } | 234 } |
| 143 //------------------------------------------------------------------------------ | 235 //------------------------------------------------------------------------------ |
| 144 // The next section provides the implementation for the private Event class. | 236 // The next section provides the implementation for the private Event class. |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 162 // certainly don't provide iterators that can be used if the identified | 254 // certainly don't provide iterators that can be used if the identified |
| 163 // element is *deleted* (removed) from the container. | 255 // element is *deleted* (removed) from the container. |
| 164 | 256 |
| 165 // It is possible to use multiple redundant containers, such as an STL list, | 257 // It is possible to use multiple redundant containers, such as an STL list, |
| 166 // and an STL map, to achieve similar container semantics. This container has | 258 // and an STL map, to achieve similar container semantics. This container has |
| 167 // only O(1) methods, while the corresponding (multiple) STL container approach | 259 // only O(1) methods, while the corresponding (multiple) STL container approach |
| 168 // would have more complex O(log(N)) methods (yeah... N isn't that large). | 260 // would have more complex O(log(N)) methods (yeah... N isn't that large). |
| 169 // Multiple containers also makes correctness more difficult to assert, as | 261 // Multiple containers also makes correctness more difficult to assert, as |
| 170 // data is redundantly stored and maintained, which is generally evil. | 262 // data is redundantly stored and maintained, which is generally evil. |
| 171 | 263 |
| 172 ConditionVariable::Event::Event() : handle_(0) { | 264 WinXPCondVar::Event::Event() : handle_(0) { |
| 173 next_ = prev_ = this; // Self referencing circular. | 265 next_ = prev_ = this; // Self referencing circular. |
| 174 } | 266 } |
| 175 | 267 |
| 176 ConditionVariable::Event::~Event() { | 268 WinXPCondVar::Event::~Event() { |
| 177 if (0 == handle_) { | 269 if (0 == handle_) { |
| 178 // This is the list holder | 270 // This is the list holder |
| 179 while (!IsEmpty()) { | 271 while (!IsEmpty()) { |
| 180 Event* cv_event = PopFront(); | 272 Event* cv_event = PopFront(); |
| 181 DCHECK(cv_event->ValidateAsItem()); | 273 DCHECK(cv_event->ValidateAsItem()); |
| 182 delete cv_event; | 274 delete cv_event; |
| 183 } | 275 } |
| 184 } | 276 } |
| 185 DCHECK(IsSingleton()); | 277 DCHECK(IsSingleton()); |
| 186 if (0 != handle_) { | 278 if (0 != handle_) { |
| 187 int ret_val = CloseHandle(handle_); | 279 int ret_val = CloseHandle(handle_); |
| 188 DCHECK(ret_val); | 280 DCHECK(ret_val); |
| 189 } | 281 } |
| 190 } | 282 } |
| 191 | 283 |
| 192 // Change a container instance permanently into an element of a list. | 284 // Change a container instance permanently into an element of a list. |
| 193 void ConditionVariable::Event::InitListElement() { | 285 void WinXPCondVar::Event::InitListElement() { |
| 194 DCHECK(!handle_); | 286 DCHECK(!handle_); |
| 195 handle_ = CreateEvent(NULL, false, false, NULL); | 287 handle_ = CreateEvent(NULL, false, false, NULL); |
| 196 DCHECK(handle_); | 288 DCHECK(handle_); |
| 197 } | 289 } |
| 198 | 290 |
| 199 // Methods for use on lists. | 291 // Methods for use on lists. |
| 200 bool ConditionVariable::Event::IsEmpty() const { | 292 bool WinXPCondVar::Event::IsEmpty() const { |
| 201 DCHECK(ValidateAsList()); | 293 DCHECK(ValidateAsList()); |
| 202 return IsSingleton(); | 294 return IsSingleton(); |
| 203 } | 295 } |
| 204 | 296 |
| 205 void ConditionVariable::Event::PushBack(Event* other) { | 297 void WinXPCondVar::Event::PushBack(Event* other) { |
| 206 DCHECK(ValidateAsList()); | 298 DCHECK(ValidateAsList()); |
| 207 DCHECK(other->ValidateAsItem()); | 299 DCHECK(other->ValidateAsItem()); |
| 208 DCHECK(other->IsSingleton()); | 300 DCHECK(other->IsSingleton()); |
| 209 // Prepare other for insertion. | 301 // Prepare other for insertion. |
| 210 other->prev_ = prev_; | 302 other->prev_ = prev_; |
| 211 other->next_ = this; | 303 other->next_ = this; |
| 212 // Cut into list. | 304 // Cut into list. |
| 213 prev_->next_ = other; | 305 prev_->next_ = other; |
| 214 prev_ = other; | 306 prev_ = other; |
| 215 DCHECK(ValidateAsDistinct(other)); | 307 DCHECK(ValidateAsDistinct(other)); |
| 216 } | 308 } |
| 217 | 309 |
| 218 ConditionVariable::Event* ConditionVariable::Event::PopFront() { | 310 WinXPCondVar::Event* WinXPCondVar::Event::PopFront() { |
| 219 DCHECK(ValidateAsList()); | 311 DCHECK(ValidateAsList()); |
| 220 DCHECK(!IsSingleton()); | 312 DCHECK(!IsSingleton()); |
| 221 return next_->Extract(); | 313 return next_->Extract(); |
| 222 } | 314 } |
| 223 | 315 |
| 224 ConditionVariable::Event* ConditionVariable::Event::PopBack() { | 316 WinXPCondVar::Event* WinXPCondVar::Event::PopBack() { |
| 225 DCHECK(ValidateAsList()); | 317 DCHECK(ValidateAsList()); |
| 226 DCHECK(!IsSingleton()); | 318 DCHECK(!IsSingleton()); |
| 227 return prev_->Extract(); | 319 return prev_->Extract(); |
| 228 } | 320 } |
| 229 | 321 |
| 230 // Methods for use on list elements. | 322 // Methods for use on list elements. |
| 231 // Accessor method. | 323 // Accessor method. |
| 232 HANDLE ConditionVariable::Event::handle() const { | 324 HANDLE WinXPCondVar::Event::handle() const { |
| 233 DCHECK(ValidateAsItem()); | 325 DCHECK(ValidateAsItem()); |
| 234 return handle_; | 326 return handle_; |
| 235 } | 327 } |
| 236 | 328 |
| 237 // Pull an element from a list (if it's in one). | 329 // Pull an element from a list (if it's in one). |
| 238 ConditionVariable::Event* ConditionVariable::Event::Extract() { | 330 WinXPCondVar::Event* WinXPCondVar::Event::Extract() { |
| 239 DCHECK(ValidateAsItem()); | 331 DCHECK(ValidateAsItem()); |
| 240 if (!IsSingleton()) { | 332 if (!IsSingleton()) { |
| 241 // Stitch neighbors together. | 333 // Stitch neighbors together. |
| 242 next_->prev_ = prev_; | 334 next_->prev_ = prev_; |
| 243 prev_->next_ = next_; | 335 prev_->next_ = next_; |
| 244 // Make extractee into a singleton. | 336 // Make extractee into a singleton. |
| 245 prev_ = next_ = this; | 337 prev_ = next_ = this; |
| 246 } | 338 } |
| 247 DCHECK(IsSingleton()); | 339 DCHECK(IsSingleton()); |
| 248 return this; | 340 return this; |
| 249 } | 341 } |
| 250 | 342 |
| 251 // Method for use on a list element or on a list. | 343 // Method for use on a list element or on a list. |
| 252 bool ConditionVariable::Event::IsSingleton() const { | 344 bool WinXPCondVar::Event::IsSingleton() const { |
| 253 DCHECK(ValidateLinks()); | 345 DCHECK(ValidateLinks()); |
| 254 return next_ == this; | 346 return next_ == this; |
| 255 } | 347 } |
| 256 | 348 |
| 257 // Provide pre/post conditions to validate correct manipulations. | 349 // Provide pre/post conditions to validate correct manipulations. |
| 258 bool ConditionVariable::Event::ValidateAsDistinct(Event* other) const { | 350 bool WinXPCondVar::Event::ValidateAsDistinct(Event* other) const { |
| 259 return ValidateLinks() && other->ValidateLinks() && (this != other); | 351 return ValidateLinks() && other->ValidateLinks() && (this != other); |
| 260 } | 352 } |
| 261 | 353 |
| 262 bool ConditionVariable::Event::ValidateAsItem() const { | 354 bool WinXPCondVar::Event::ValidateAsItem() const { |
| 263 return (0 != handle_) && ValidateLinks(); | 355 return (0 != handle_) && ValidateLinks(); |
| 264 } | 356 } |
| 265 | 357 |
| 266 bool ConditionVariable::Event::ValidateAsList() const { | 358 bool WinXPCondVar::Event::ValidateAsList() const { |
| 267 return (0 == handle_) && ValidateLinks(); | 359 return (0 == handle_) && ValidateLinks(); |
| 268 } | 360 } |
| 269 | 361 |
| 270 bool ConditionVariable::Event::ValidateLinks() const { | 362 bool WinXPCondVar::Event::ValidateLinks() const { |
| 271 // Make sure both of our neighbors have links that point back to us. | 363 // Make sure both of our neighbors have links that point back to us. |
| 272 // We don't do the O(n) check and traverse the whole loop, and instead only | 364 // We don't do the O(n) check and traverse the whole loop, and instead only |
| 273 // do a local check to (and returning from) our immediate neighbors. | 365 // do a local check to (and returning from) our immediate neighbors. |
| 274 return (next_->prev_ == this) && (prev_->next_ == this); | 366 return (next_->prev_ == this) && (prev_->next_ == this); |
| 275 } | 367 } |
| 276 | 368 |
| 277 | 369 |
| 278 /* | 370 /* |
| 279 FAQ On subtle implementation details: | 371 FAQ On WinXPCondVar subtle implementation details: |
| 280 | 372 |
| 281 1) What makes this problem subtle? Please take a look at "Strategies | 373 1) What makes this problem subtle? Please take a look at "Strategies |
| 282 for Implementing POSIX Condition Variables on Win32" by Douglas | 374 for Implementing POSIX Condition Variables on Win32" by Douglas |
| 283 C. Schmidt and Irfan Pyarali. | 375 C. Schmidt and Irfan Pyarali. |
| 284 http://www.cs.wustl.edu/~schmidt/win32-cv-1.html It includes | 376 http://www.cs.wustl.edu/~schmidt/win32-cv-1.html It includes |
| 285 discussions of numerous flawed strategies for implementing this | 377 discussions of numerous flawed strategies for implementing this |
| 286 functionality. I'm not convinced that even the final proposed | 378 functionality. I'm not convinced that even the final proposed |
| 287 implementation has semantics that are as nice as this implementation | 379 implementation has semantics that are as nice as this implementation |
| 288 (especially with regard to Broadcast() and the impact on threads that | 380 (especially with regard to Broadcast() and the impact on threads that |
| 289 try to Wait() after a Broadcast() has been called, but before all the | 381 try to Wait() after a Broadcast() has been called, but before all the |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 437 use a complex and relatively low efficiency container when a doubly linked list | 529 use a complex and relatively low efficiency container when a doubly linked list |
| 438 provided O(1) performance in all required operations. Since other operations | 530 provided O(1) performance in all required operations. Since other operations |
| 439 to provide performance-and/or-fairness required queue (FIFO) and list (LIFO) | 531 to provide performance-and/or-fairness required queue (FIFO) and list (LIFO) |
| 440 containers, I would also have needed to use an STL list/queue as well as an STL | 532 containers, I would also have needed to use an STL list/queue as well as an STL |
| 441 map. In the end I decided it would be "fun" to just do it right, and I | 533 map. In the end I decided it would be "fun" to just do it right, and I |
| 442 put so many assertions (DCHECKs) into the container class that it is trivial to | 534 put so many assertions (DCHECKs) into the container class that it is trivial to |
| 443 code review and validate its correctness. | 535 code review and validate its correctness. |
| 444 | 536 |
| 445 */ | 537 */ |
| 446 | 538 |
| 539 ConditionVariable::ConditionVariable(Lock* user_lock) | |
| 540 : impl_(new WinXPCondVar(user_lock)) { | |
| 541 } | |
| 542 | |
| 543 ConditionVariable::~ConditionVariable() { | |
| 544 delete impl_; | |
| 545 } | |
| 546 | |
| 547 void ConditionVariable::Wait() { | |
| 548 impl_->Wait(); | |
| 549 } | |
| 550 | |
| 551 void ConditionVariable::TimedWait(const TimeDelta& max_time) { | |
| 552 impl_->TimedWait(max_time); | |
| 553 } | |
| 554 | |
| 555 void ConditionVariable::Broadcast() { | |
| 556 impl_->Broadcast(); | |
| 557 } | |
| 558 | |
| 559 void ConditionVariable::Signal() { | |
| 560 impl_->Signal(); | |
| 561 } | |
| 562 | |
| 447 } // namespace base | 563 } // namespace base |
| OLD | NEW |