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 |