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  }