Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(177)

Side by Side Diff: base/synchronization/condition_variable_win.cc

Issue 8823012: Prep work for win7-specific condition variable (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 9 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « base/synchronization/condition_variable.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
OLDNEW
« no previous file with comments | « base/synchronization/condition_variable.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698