github.com/cellofellow/gopkg@v0.0.0-20140722061823-eec0544a62ad/database/leveldb/src/port/port_windows.cc (about) 1 // LevelDB Copyright (c) 2011 The LevelDB Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. See the AUTHORS file for names of contributors. 4 // 5 // See port_example.h for documentation for the following types/functions. 6 7 // Redistribution and use in source and binary forms, with or without 8 // modification, are permitted provided that the following conditions are met: 9 // 10 // * Redistributions of source code must retain the above copyright 11 // notice, this list of conditions and the following disclaimer. 12 // * Redistributions in binary form must reproduce the above copyright 13 // notice, this list of conditions and the following disclaimer in the 14 // documentation and/or other materials provided with the distribution. 15 // * Neither the name of the University of California, Berkeley nor the 16 // names of its contributors may be used to endorse or promote products 17 // derived from this software without specific prior written permission. 18 // 19 // THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY 20 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 21 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 22 // DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY 23 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 26 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 28 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 // 30 31 #include "port/port_windows.h" 32 #include "util/mutexlock.h" 33 34 #include <stack> 35 #include <cassert> 36 37 namespace leveldb { 38 namespace port { 39 40 // MutexUnlock is a helper that will Release() the |lock| argument in the 41 // constructor, and re-Acquire() it in the destructor. 42 class MutexUnlock { 43 public: 44 explicit MutexUnlock(Mutex *mu) : mu_(mu) { 45 // We require our caller to have the lock. 46 mu_->AssertHeld(); 47 mu_->Unlock(); 48 } 49 50 ~MutexUnlock() { 51 mu_->Lock(); 52 } 53 54 private: 55 Mutex *const mu_; 56 // No copying allowed 57 MutexUnlock(const MutexUnlock&); 58 void operator=(const MutexUnlock&); 59 }; 60 61 CondVar::CondVar(Mutex* user_lock) 62 : user_lock_(*user_lock), 63 run_state_(RUNNING), 64 allocation_counter_(0), 65 recycling_list_size_(0) { 66 } 67 68 CondVar::~CondVar() { 69 MutexLock auto_lock(&internal_lock_); 70 run_state_ = SHUTDOWN; // Prevent any more waiting. 71 if (recycling_list_size_ != allocation_counter_) { // Rare shutdown problem. 72 // There are threads of execution still in this->TimedWait() and yet the 73 // caller has instigated the destruction of this instance :-/. 74 // A common reason for such "overly hasty" destruction is that the caller 75 // was not willing to wait for all the threads to terminate. Such hasty 76 // actions are a violation of our usage contract, but we'll give the 77 // waiting thread(s) one last chance to exit gracefully (prior to our 78 // destruction). 79 // Note: waiting_list_ *might* be empty, but recycling is still pending. 80 MutexUnlock auto_unlock(&internal_lock_); 81 SignalAll(); // Make sure all waiting threads have been signaled. 82 Sleep(10); // Give threads a chance to grab internal_lock_. 83 // All contained threads should be blocked on user_lock_ by now :-). 84 } // Reacquire internal_lock_. 85 } 86 87 void CondVar::TimedWait(const int64_t max_time_in_ms) { 88 Event* waiting_event; 89 HANDLE handle; 90 { 91 MutexLock auto_lock(&internal_lock_); 92 if (RUNNING != run_state_) return; // Destruction in progress. 93 waiting_event = GetEventForWaiting(); 94 handle = waiting_event->handle(); 95 assert(handle); 96 } // Release internal_lock. 97 98 { 99 MutexUnlock unlock(&user_lock_); // Release caller's lock 100 WaitForSingleObject(handle, static_cast<DWORD>(max_time_in_ms)); 101 // Minimize spurious signal creation window by recycling asap. 102 MutexLock auto_lock(&internal_lock_); 103 RecycleEvent(waiting_event); 104 // Release internal_lock_ 105 } // Reacquire callers lock to depth at entry. 106 } 107 108 // SignalAll() is guaranteed to signal all threads that were waiting (i.e., had 109 // a cv_event internally allocated for them) before SignalAll() was called. 110 void CondVar::SignalAll() { 111 std::stack<HANDLE> handles; // See FAQ-question-10. 112 { 113 MutexLock auto_lock(&internal_lock_); 114 if (waiting_list_.IsEmpty()) 115 return; 116 while (!waiting_list_.IsEmpty()) 117 // This is not a leak from waiting_list_. See FAQ-question 12. 118 handles.push(waiting_list_.PopBack()->handle()); 119 } // Release internal_lock_. 120 while (!handles.empty()) { 121 SetEvent(handles.top()); 122 handles.pop(); 123 } 124 } 125 126 // Signal() will select one of the waiting threads, and signal it (signal its 127 // cv_event). For better performance we signal the thread that went to sleep 128 // most recently (LIFO). If we want fairness, then we wake the thread that has 129 // been sleeping the longest (FIFO). 130 void CondVar::Signal() { 131 HANDLE handle; 132 { 133 MutexLock auto_lock(&internal_lock_); 134 if (waiting_list_.IsEmpty()) 135 return; // No one to signal. 136 // Only performance option should be used. 137 // This is not a leak from waiting_list. See FAQ-question 12. 138 handle = waiting_list_.PopBack()->handle(); // LIFO. 139 } // Release internal_lock_. 140 SetEvent(handle); 141 } 142 143 // GetEventForWaiting() provides a unique cv_event for any caller that needs to 144 // wait. This means that (worst case) we may over time create as many cv_event 145 // objects as there are threads simultaneously using this instance's Wait() 146 // functionality. 147 CondVar::Event* CondVar::GetEventForWaiting() { 148 // We hold internal_lock, courtesy of Wait(). 149 Event* cv_event; 150 if (0 == recycling_list_size_) { 151 assert(recycling_list_.IsEmpty()); 152 cv_event = new Event(); 153 cv_event->InitListElement(); 154 allocation_counter_++; 155 assert(cv_event->handle()); 156 } else { 157 cv_event = recycling_list_.PopFront(); 158 recycling_list_size_--; 159 } 160 waiting_list_.PushBack(cv_event); 161 return cv_event; 162 } 163 164 // RecycleEvent() takes a cv_event that was previously used for Wait()ing, and 165 // recycles it for use in future Wait() calls for this or other threads. 166 // Note that there is a tiny chance that the cv_event is still signaled when we 167 // obtain it, and that can cause spurious signals (if/when we re-use the 168 // cv_event), but such is quite rare (see FAQ-question-5). 169 void CondVar::RecycleEvent(Event* used_event) { 170 // We hold internal_lock, courtesy of Wait(). 171 // If the cv_event timed out, then it is necessary to remove it from 172 // waiting_list_. If it was selected by SignalAll() or Signal(), then it is 173 // already gone. 174 used_event->Extract(); // Possibly redundant 175 recycling_list_.PushBack(used_event); 176 recycling_list_size_++; 177 } 178 //------------------------------------------------------------------------------ 179 // The next section provides the implementation for the private Event class. 180 //------------------------------------------------------------------------------ 181 182 // Event provides a doubly-linked-list of events for use exclusively by the 183 // CondVar class. 184 185 // This custom container was crafted because no simple combination of STL 186 // classes appeared to support the functionality required. The specific 187 // unusual requirement for a linked-list-class is support for the Extract() 188 // method, which can remove an element from a list, potentially for insertion 189 // into a second list. Most critically, the Extract() method is idempotent, 190 // turning the indicated element into an extracted singleton whether it was 191 // contained in a list or not. This functionality allows one (or more) of 192 // threads to do the extraction. The iterator that identifies this extractable 193 // element (in this case, a pointer to the list element) can be used after 194 // arbitrary manipulation of the (possibly) enclosing list container. In 195 // general, STL containers do not provide iterators that can be used across 196 // modifications (insertions/extractions) of the enclosing containers, and 197 // certainly don't provide iterators that can be used if the identified 198 // element is *deleted* (removed) from the container. 199 200 // It is possible to use multiple redundant containers, such as an STL list, 201 // and an STL map, to achieve similar container semantics. This container has 202 // only O(1) methods, while the corresponding (multiple) STL container approach 203 // would have more complex O(log(N)) methods (yeah... N isn't that large). 204 // Multiple containers also makes correctness more difficult to assert, as 205 // data is redundantly stored and maintained, which is generally evil. 206 207 CondVar::Event::Event() : handle_(0) { 208 next_ = prev_ = this; // Self referencing circular. 209 } 210 211 CondVar::Event::~Event() { 212 if (0 == handle_) { 213 // This is the list holder 214 while (!IsEmpty()) { 215 Event* cv_event = PopFront(); 216 assert(cv_event->ValidateAsItem()); 217 delete cv_event; 218 } 219 } 220 assert(IsSingleton()); 221 if (0 != handle_) { 222 int ret_val = CloseHandle(handle_); 223 assert(ret_val); 224 } 225 } 226 227 // Change a container instance permanently into an element of a list. 228 void CondVar::Event::InitListElement() { 229 assert(!handle_); 230 handle_ = CreateEvent(NULL, false, false, NULL); 231 assert(handle_); 232 } 233 234 // Methods for use on lists. 235 bool CondVar::Event::IsEmpty() const { 236 assert(ValidateAsList()); 237 return IsSingleton(); 238 } 239 240 void CondVar::Event::PushBack(Event* other) { 241 assert(ValidateAsList()); 242 assert(other->ValidateAsItem()); 243 assert(other->IsSingleton()); 244 // Prepare other for insertion. 245 other->prev_ = prev_; 246 other->next_ = this; 247 // Cut into list. 248 prev_->next_ = other; 249 prev_ = other; 250 assert(ValidateAsDistinct(other)); 251 } 252 253 CondVar::Event* CondVar::Event::PopFront() { 254 assert(ValidateAsList()); 255 assert(!IsSingleton()); 256 return next_->Extract(); 257 } 258 259 CondVar::Event* CondVar::Event::PopBack() { 260 assert(ValidateAsList()); 261 assert(!IsSingleton()); 262 return prev_->Extract(); 263 } 264 265 // Methods for use on list elements. 266 // Accessor method. 267 HANDLE CondVar::Event::handle() const { 268 assert(ValidateAsItem()); 269 return handle_; 270 } 271 272 // Pull an element from a list (if it's in one). 273 CondVar::Event* CondVar::Event::Extract() { 274 assert(ValidateAsItem()); 275 if (!IsSingleton()) { 276 // Stitch neighbors together. 277 next_->prev_ = prev_; 278 prev_->next_ = next_; 279 // Make extractee into a singleton. 280 prev_ = next_ = this; 281 } 282 assert(IsSingleton()); 283 return this; 284 } 285 286 // Method for use on a list element or on a list. 287 bool CondVar::Event::IsSingleton() const { 288 assert(ValidateLinks()); 289 return next_ == this; 290 } 291 292 // Provide pre/post conditions to validate correct manipulations. 293 bool CondVar::Event::ValidateAsDistinct(Event* other) const { 294 return ValidateLinks() && other->ValidateLinks() && (this != other); 295 } 296 297 bool CondVar::Event::ValidateAsItem() const { 298 return (0 != handle_) && ValidateLinks(); 299 } 300 301 bool CondVar::Event::ValidateAsList() const { 302 return (0 == handle_) && ValidateLinks(); 303 } 304 305 bool CondVar::Event::ValidateLinks() const { 306 // Make sure both of our neighbors have links that point back to us. 307 // We don't do the O(n) check and traverse the whole loop, and instead only 308 // do a local check to (and returning from) our immediate neighbors. 309 return (next_->prev_ == this) && (prev_->next_ == this); 310 } 311 312 enum InitializationState { 313 Uninitialized = 0, 314 Running = 1, 315 Initialized = 2, 316 }; 317 318 void InitOnce(OnceType* once, void (*initializer)()) { 319 //static_assert(Uninitialized == LEVELDB_ONCE_INIT, "Invalid uninitialized state value"); 320 InitializationState state = static_cast<InitializationState>(InterlockedCompareExchange(once, Running, Uninitialized)); 321 322 if (state == Uninitialized) { 323 initializer(); 324 *once = Initialized; 325 } 326 327 if (state == Running) { 328 while(*once != Initialized) { 329 Sleep(0); // yield 330 } 331 } 332 333 assert(*once == Initialized); 334 } 335 336 /* 337 FAQ On subtle implementation details: 338 339 1) What makes this problem subtle? Please take a look at "Strategies 340 for Implementing POSIX Condition Variables on Win32" by Douglas 341 C. Schmidt and Irfan Pyarali. 342 http://www.cs.wustl.edu/~schmidt/win32-cv-1.html It includes 343 discussions of numerous flawed strategies for implementing this 344 functionality. I'm not convinced that even the final proposed 345 implementation has semantics that are as nice as this implementation 346 (especially with regard to SignalAll() and the impact on threads that 347 try to Wait() after a SignalAll() has been called, but before all the 348 original waiting threads have been signaled). 349 350 2) Why can't you use a single wait_event for all threads that call 351 Wait()? See FAQ-question-1, or consider the following: If a single 352 event were used, then numerous threads calling Wait() could release 353 their cs locks, and be preempted just before calling 354 WaitForSingleObject(). If a call to SignalAll() was then presented on 355 a second thread, it would be impossible to actually signal all 356 waiting(?) threads. Some number of SetEvent() calls *could* be made, 357 but there could be no guarantee that those led to to more than one 358 signaled thread (SetEvent()'s may be discarded after the first!), and 359 there could be no guarantee that the SetEvent() calls didn't just 360 awaken "other" threads that hadn't even started waiting yet (oops). 361 Without any limit on the number of requisite SetEvent() calls, the 362 system would be forced to do many such calls, allowing many new waits 363 to receive spurious signals. 364 365 3) How does this implementation cause spurious signal events? The 366 cause in this implementation involves a race between a signal via 367 time-out and a signal via Signal() or SignalAll(). The series of 368 actions leading to this are: 369 370 a) Timer fires, and a waiting thread exits the line of code: 371 372 WaitForSingleObject(waiting_event, max_time.InMilliseconds()); 373 374 b) That thread (in (a)) is randomly pre-empted after the above line, 375 leaving the waiting_event reset (unsignaled) and still in the 376 waiting_list_. 377 378 c) A call to Signal() (or SignalAll()) on a second thread proceeds, and 379 selects the waiting cv_event (identified in step (b)) as the event to revive 380 via a call to SetEvent(). 381 382 d) The Signal() method (step c) calls SetEvent() on waiting_event (step b). 383 384 e) The waiting cv_event (step b) is now signaled, but no thread is 385 waiting on it. 386 387 f) When that waiting_event (step b) is reused, it will immediately 388 be signaled (spuriously). 389 390 391 4) Why do you recycle events, and cause spurious signals? First off, 392 the spurious events are very rare. They can only (I think) appear 393 when the race described in FAQ-question-3 takes place. This should be 394 very rare. Most(?) uses will involve only timer expiration, or only 395 Signal/SignalAll() actions. When both are used, it will be rare that 396 the race will appear, and it would require MANY Wait() and signaling 397 activities. If this implementation did not recycle events, then it 398 would have to create and destroy events for every call to Wait(). 399 That allocation/deallocation and associated construction/destruction 400 would be costly (per wait), and would only be a rare benefit (when the 401 race was "lost" and a spurious signal took place). That would be bad 402 (IMO) optimization trade-off. Finally, such spurious events are 403 allowed by the specification of condition variables (such as 404 implemented in Vista), and hence it is better if any user accommodates 405 such spurious events (see usage note in condition_variable.h). 406 407 5) Why don't you reset events when you are about to recycle them, or 408 about to reuse them, so that the spurious signals don't take place? 409 The thread described in FAQ-question-3 step c may be pre-empted for an 410 arbitrary length of time before proceeding to step d. As a result, 411 the wait_event may actually be re-used *before* step (e) is reached. 412 As a result, calling reset would not help significantly. 413 414 6) How is it that the callers lock is released atomically with the 415 entry into a wait state? We commit to the wait activity when we 416 allocate the wait_event for use in a given call to Wait(). This 417 allocation takes place before the caller's lock is released (and 418 actually before our internal_lock_ is released). That allocation is 419 the defining moment when "the wait state has been entered," as that 420 thread *can* now be signaled by a call to SignalAll() or Signal(). 421 Hence we actually "commit to wait" before releasing the lock, making 422 the pair effectively atomic. 423 424 8) Why do you need to lock your data structures during waiting, as the 425 caller is already in possession of a lock? We need to Acquire() and 426 Release() our internal lock during Signal() and SignalAll(). If we tried 427 to use a callers lock for this purpose, we might conflict with their 428 external use of the lock. For example, the caller may use to consistently 429 hold a lock on one thread while calling Signal() on another, and that would 430 block Signal(). 431 432 9) Couldn't a more efficient implementation be provided if you 433 preclude using more than one external lock in conjunction with a 434 single ConditionVariable instance? Yes, at least it could be viewed 435 as a simpler API (since you don't have to reiterate the lock argument 436 in each Wait() call). One of the constructors now takes a specific 437 lock as an argument, and a there are corresponding Wait() calls that 438 don't specify a lock now. It turns that the resulting implmentation 439 can't be made more efficient, as the internal lock needs to be used by 440 Signal() and SignalAll(), to access internal data structures. As a 441 result, I was not able to utilize the user supplied lock (which is 442 being used by the user elsewhere presumably) to protect the private 443 member access. 444 445 9) Since you have a second lock, how can be be sure that there is no 446 possible deadlock scenario? Our internal_lock_ is always the last 447 lock acquired, and the first one released, and hence a deadlock (due 448 to critical section problems) is impossible as a consequence of our 449 lock. 450 451 10) When doing a SignalAll(), why did you copy all the events into 452 an STL queue, rather than making a linked-loop, and iterating over it? 453 The iterating during SignalAll() is done so outside the protection 454 of the internal lock. As a result, other threads, such as the thread 455 wherein a related event is waiting, could asynchronously manipulate 456 the links around a cv_event. As a result, the link structure cannot 457 be used outside a lock. SignalAll() could iterate over waiting 458 events by cycling in-and-out of the protection of the internal_lock, 459 but that appears more expensive than copying the list into an STL 460 stack. 461 462 11) Why did the lock.h file need to be modified so much for this 463 change? Central to a Condition Variable is the atomic release of a 464 lock during a Wait(). This places Wait() functionality exactly 465 mid-way between the two classes, Lock and Condition Variable. Given 466 that there can be nested Acquire()'s of locks, and Wait() had to 467 Release() completely a held lock, it was necessary to augment the Lock 468 class with a recursion counter. Even more subtle is the fact that the 469 recursion counter (in a Lock) must be protected, as many threads can 470 access it asynchronously. As a positive fallout of this, there are 471 now some DCHECKS to be sure no one Release()s a Lock more than they 472 Acquire()ed it, and there is ifdef'ed functionality that can detect 473 nested locks (legal under windows, but not under Posix). 474 475 12) Why is it that the cv_events removed from list in SignalAll() and Signal() 476 are not leaked? How are they recovered?? The cv_events that appear to leak are 477 taken from the waiting_list_. For each element in that list, there is currently 478 a thread in or around the WaitForSingleObject() call of Wait(), and those 479 threads have references to these otherwise leaked events. They are passed as 480 arguments to be recycled just aftre returning from WaitForSingleObject(). 481 482 13) Why did you use a custom container class (the linked list), when STL has 483 perfectly good containers, such as an STL list? The STL list, as with any 484 container, does not guarantee the utility of an iterator across manipulation 485 (such as insertions and deletions) of the underlying container. The custom 486 double-linked-list container provided that assurance. I don't believe any 487 combination of STL containers provided the services that were needed at the same 488 O(1) efficiency as the custom linked list. The unusual requirement 489 for the container class is that a reference to an item within a container (an 490 iterator) needed to be maintained across an arbitrary manipulation of the 491 container. This requirement exposes itself in the Wait() method, where a 492 waiting_event must be selected prior to the WaitForSingleObject(), and then it 493 must be used as part of recycling to remove the related instance from the 494 waiting_list. A hash table (STL map) could be used, but I was embarrased to 495 use a complex and relatively low efficiency container when a doubly linked list 496 provided O(1) performance in all required operations. Since other operations 497 to provide performance-and/or-fairness required queue (FIFO) and list (LIFO) 498 containers, I would also have needed to use an STL list/queue as well as an STL 499 map. In the end I decided it would be "fun" to just do it right, and I 500 put so many assertions (DCHECKs) into the container class that it is trivial to 501 code review and validate its correctness. 502 503 */ 504 505 } 506 }