15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2011 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/synchronization/condition_variable.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <windows.h>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stack>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/compiler_specific.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/synchronization/lock.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/threading/thread_restrictions.h"
14eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/time/time.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We can't use the linker supported delay-load for kernel32 so all this
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// cruft here is to manually late-bind the needed functions.
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef void (WINAPI *InitializeConditionVariableFn)(PCONDITION_VARIABLE);
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef BOOL (WINAPI *SleepConditionVariableCSFn)(PCONDITION_VARIABLE,
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                  PCRITICAL_SECTION, DWORD);
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef void (WINAPI *WakeConditionVariableFn)(PCONDITION_VARIABLE);
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef void (WINAPI *WakeAllConditionVariableFn)(PCONDITION_VARIABLE);
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)InitializeConditionVariableFn initialize_condition_variable_fn;
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)SleepConditionVariableCSFn sleep_condition_variable_fn;
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WakeConditionVariableFn wake_condition_variable_fn;
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WakeAllConditionVariableFn wake_all_condition_variable_fn;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BindVistaCondVarFunctions() {
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  initialize_condition_variable_fn =
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reinterpret_cast<InitializeConditionVariableFn>(
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          GetProcAddress(kernel32, "InitializeConditionVariable"));
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!initialize_condition_variable_fn)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  sleep_condition_variable_fn =
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reinterpret_cast<SleepConditionVariableCSFn>(
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          GetProcAddress(kernel32, "SleepConditionVariableCS"));
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!sleep_condition_variable_fn)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wake_condition_variable_fn =
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reinterpret_cast<WakeConditionVariableFn>(
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          GetProcAddress(kernel32, "WakeConditionVariable"));
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!wake_condition_variable_fn)
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wake_all_condition_variable_fn =
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      reinterpret_cast<WakeAllConditionVariableFn>(
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          GetProcAddress(kernel32, "WakeAllConditionVariable"));
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!wake_all_condition_variable_fn)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace.
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace base {
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Abstract base class of the pimpl idiom.
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ConditionVarImpl {
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~ConditionVarImpl() {};
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void Wait() = 0;
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void TimedWait(const TimeDelta& max_time) = 0;
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void Broadcast() = 0;
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void Signal() = 0;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)///////////////////////////////////////////////////////////////////////////////
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Windows Vista and Win7 implementation.
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)///////////////////////////////////////////////////////////////////////////////
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class WinVistaCondVar: public ConditionVarImpl {
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WinVistaCondVar(Lock* user_lock);
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~WinVistaCondVar() {};
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Overridden from ConditionVarImpl.
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void Wait() OVERRIDE;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void TimedWait(const TimeDelta& max_time) OVERRIDE;
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void Broadcast() OVERRIDE;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void Signal() OVERRIDE;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Lock& user_lock_;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CONDITION_VARIABLE cv_;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WinVistaCondVar::WinVistaCondVar(Lock* user_lock)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : user_lock_(*user_lock) {
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  initialize_condition_variable_fn(&cv_);
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(user_lock);
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WinVistaCondVar::Wait() {
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TimedWait(TimeDelta::FromMilliseconds(INFINITE));
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WinVistaCondVar::TimedWait(const TimeDelta& max_time) {
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::AssertWaitAllowed();
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DWORD timeout = static_cast<DWORD>(max_time.InMilliseconds());
100d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  CRITICAL_SECTION* cs = user_lock_.lock_.native_handle();
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  user_lock_.CheckHeldAndUnmark();
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (FALSE == sleep_condition_variable_fn(&cv_, cs, timeout)) {
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(GetLastError() != WAIT_TIMEOUT);
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  user_lock_.CheckUnheldAndMark();
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WinVistaCondVar::Broadcast() {
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wake_all_condition_variable_fn(&cv_);
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WinVistaCondVar::Signal() {
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  wake_condition_variable_fn(&cv_);
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)///////////////////////////////////////////////////////////////////////////////
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Windows XP implementation.
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)///////////////////////////////////////////////////////////////////////////////
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class WinXPCondVar : public ConditionVarImpl {
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WinXPCondVar(Lock* user_lock);
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~WinXPCondVar();
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Overridden from ConditionVarImpl.
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void Wait() OVERRIDE;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void TimedWait(const TimeDelta& max_time) OVERRIDE;
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void Broadcast() OVERRIDE;
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void Signal() OVERRIDE;
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Define Event class that is used to form circularly linked lists.
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The list container is an element with NULL as its handle_ value.
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The actual list elements have a non-zero handle_ value.
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // All calls to methods MUST be done under protection of a lock so that links
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // can be validated.  Without the lock, some links might asynchronously
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // change, and the assertions would fail (as would list change operations).
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  class Event {
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   public:
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Default constructor with no arguments creates a list container.
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Event();
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ~Event();
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // InitListElement transitions an instance from a container, to an element.
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void InitListElement();
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Methods for use on lists.
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool IsEmpty() const;
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void PushBack(Event* other);
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Event* PopFront();
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Event* PopBack();
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Methods for use on list elements.
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Accessor method.
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HANDLE handle() const;
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Pull an element from a list (if it's in one).
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Event* Extract();
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Method for use on a list element or on a list.
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool IsSingleton() const;
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)   private:
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Provide pre/post conditions to validate correct manipulations.
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool ValidateAsDistinct(Event* other) const;
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool ValidateAsItem() const;
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool ValidateAsList() const;
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool ValidateLinks() const;
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    HANDLE handle_;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Event* next_;
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Event* prev_;
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DISALLOW_COPY_AND_ASSIGN(Event);
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note that RUNNING is an unlikely number to have in RAM by accident.
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This helps with defensive destructor coding in the face of user error.
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  enum RunState { SHUTDOWN = 0, RUNNING = 64213 };
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Internal implementation methods supporting Wait().
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Event* GetEventForWaiting();
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void RecycleEvent(Event* used_event);
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  RunState run_state_;
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Private critical section for access to member data.
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Lock internal_lock_;
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Lock that is acquired before calling Wait().
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Lock& user_lock_;
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Events that threads are blocked on.
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Event waiting_list_;
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Free list for old events.
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Event recycling_list_;
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int recycling_list_size_;
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The number of allocated, but not yet deleted events.
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int allocation_counter_;
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WinXPCondVar::WinXPCondVar(Lock* user_lock)
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : user_lock_(*user_lock),
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      run_state_(RUNNING),
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      allocation_counter_(0),
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      recycling_list_size_(0) {
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(user_lock);
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WinXPCondVar::~WinXPCondVar() {
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  AutoLock auto_lock(internal_lock_);
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  run_state_ = SHUTDOWN;  // Prevent any more waiting.
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(recycling_list_size_, allocation_counter_);
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (recycling_list_size_ != allocation_counter_) {  // Rare shutdown problem.
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // There are threads of execution still in this->TimedWait() and yet the
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // caller has instigated the destruction of this instance :-/.
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // A common reason for such "overly hasty" destruction is that the caller
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // was not willing to wait for all the threads to terminate.  Such hasty
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // actions are a violation of our usage contract, but we'll give the
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // waiting thread(s) one last chance to exit gracefully (prior to our
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // destruction).
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Note: waiting_list_ *might* be empty, but recycling is still pending.
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AutoUnlock auto_unlock(internal_lock_);
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Broadcast();  // Make sure all waiting threads have been signaled.
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Sleep(10);  // Give threads a chance to grab internal_lock_.
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // All contained threads should be blocked on user_lock_ by now :-).
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }  // Reacquire internal_lock_.
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_EQ(recycling_list_size_, allocation_counter_);
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WinXPCondVar::Wait() {
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Default to "wait forever" timing, which means have to get a Signal()
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // or Broadcast() to come out of this wait state.
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TimedWait(TimeDelta::FromMilliseconds(INFINITE));
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WinXPCondVar::TimedWait(const TimeDelta& max_time) {
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::ThreadRestrictions::AssertWaitAllowed();
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Event* waiting_event;
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HANDLE handle;
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AutoLock auto_lock(internal_lock_);
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (RUNNING != run_state_) return;  // Destruction in progress.
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    waiting_event = GetEventForWaiting();
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    handle = waiting_event->handle();
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(handle);
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }  // Release internal_lock.
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AutoUnlock unlock(user_lock_);  // Release caller's lock
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    WaitForSingleObject(handle, static_cast<DWORD>(max_time.InMilliseconds()));
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Minimize spurious signal creation window by recycling asap.
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AutoLock auto_lock(internal_lock_);
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    RecycleEvent(waiting_event);
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Release internal_lock_
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }  // Reacquire callers lock to depth at entry.
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Broadcast() is guaranteed to signal all threads that were waiting (i.e., had
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// a cv_event internally allocated for them) before Broadcast() was called.
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WinXPCondVar::Broadcast() {
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::stack<HANDLE> handles;  // See FAQ-question-10.
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AutoLock auto_lock(internal_lock_);
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (waiting_list_.IsEmpty())
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while (!waiting_list_.IsEmpty())
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // This is not a leak from waiting_list_.  See FAQ-question 12.
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      handles.push(waiting_list_.PopBack()->handle());
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }  // Release internal_lock_.
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  while (!handles.empty()) {
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetEvent(handles.top());
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    handles.pop();
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Signal() will select one of the waiting threads, and signal it (signal its
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// cv_event).  For better performance we signal the thread that went to sleep
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// most recently (LIFO).  If we want fairness, then we wake the thread that has
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// been sleeping the longest (FIFO).
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WinXPCondVar::Signal() {
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HANDLE handle;
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  {
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    AutoLock auto_lock(internal_lock_);
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (waiting_list_.IsEmpty())
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return;  // No one to signal.
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Only performance option should be used.
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This is not a leak from waiting_list.  See FAQ-question 12.
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     handle = waiting_list_.PopBack()->handle();  // LIFO.
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }  // Release internal_lock_.
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetEvent(handle);
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// GetEventForWaiting() provides a unique cv_event for any caller that needs to
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// wait.  This means that (worst case) we may over time create as many cv_event
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// objects as there are threads simultaneously using this instance's Wait()
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// functionality.
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WinXPCondVar::Event* WinXPCondVar::GetEventForWaiting() {
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We hold internal_lock, courtesy of Wait().
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Event* cv_event;
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (0 == recycling_list_size_) {
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(recycling_list_.IsEmpty());
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cv_event = new Event();
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cv_event->InitListElement();
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    allocation_counter_++;
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(cv_event->handle());
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cv_event = recycling_list_.PopFront();
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    recycling_list_size_--;
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  waiting_list_.PushBack(cv_event);
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return cv_event;
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// RecycleEvent() takes a cv_event that was previously used for Wait()ing, and
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// recycles it for use in future Wait() calls for this or other threads.
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Note that there is a tiny chance that the cv_event is still signaled when we
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// obtain it, and that can cause spurious signals (if/when we re-use the
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// cv_event), but such is quite rare (see FAQ-question-5).
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WinXPCondVar::RecycleEvent(Event* used_event) {
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We hold internal_lock, courtesy of Wait().
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If the cv_event timed out, then it is necessary to remove it from
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // waiting_list_.  If it was selected by Broadcast() or Signal(), then it is
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // already gone.
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  used_event->Extract();  // Possibly redundant
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  recycling_list_.PushBack(used_event);
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  recycling_list_size_++;
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//------------------------------------------------------------------------------
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The next section provides the implementation for the private Event class.
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//------------------------------------------------------------------------------
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Event provides a doubly-linked-list of events for use exclusively by the
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ConditionVariable class.
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This custom container was crafted because no simple combination of STL
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// classes appeared to support the functionality required.  The specific
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// unusual requirement for a linked-list-class is support for the Extract()
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// method, which can remove an element from a list, potentially for insertion
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// into a second list.  Most critically, the Extract() method is idempotent,
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// turning the indicated element into an extracted singleton whether it was
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// contained in a list or not.  This functionality allows one (or more) of
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// threads to do the extraction.  The iterator that identifies this extractable
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// element (in this case, a pointer to the list element) can be used after
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// arbitrary manipulation of the (possibly) enclosing list container.  In
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// general, STL containers do not provide iterators that can be used across
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// modifications (insertions/extractions) of the enclosing containers, and
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// certainly don't provide iterators that can be used if the identified
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// element is *deleted* (removed) from the container.
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// It is possible to use multiple redundant containers, such as an STL list,
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and an STL map, to achieve similar container semantics.  This container has
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// only O(1) methods, while the corresponding (multiple) STL container approach
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// would have more complex O(log(N)) methods (yeah... N isn't that large).
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Multiple containers also makes correctness more difficult to assert, as
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// data is redundantly stored and maintained, which is generally evil.
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WinXPCondVar::Event::Event() : handle_(0) {
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  next_ = prev_ = this;  // Self referencing circular.
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WinXPCondVar::Event::~Event() {
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (0 == handle_) {
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // This is the list holder
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    while (!IsEmpty()) {
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Event* cv_event = PopFront();
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DCHECK(cv_event->ValidateAsItem());
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delete cv_event;
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(IsSingleton());
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (0 != handle_) {
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int ret_val = CloseHandle(handle_);
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(ret_val);
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Change a container instance permanently into an element of a list.
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WinXPCondVar::Event::InitListElement() {
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!handle_);
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  handle_ = CreateEvent(NULL, false, false, NULL);
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(handle_);
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Methods for use on lists.
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool WinXPCondVar::Event::IsEmpty() const {
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(ValidateAsList());
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return IsSingleton();
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void WinXPCondVar::Event::PushBack(Event* other) {
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(ValidateAsList());
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(other->ValidateAsItem());
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(other->IsSingleton());
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Prepare other for insertion.
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  other->prev_ = prev_;
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  other->next_ = this;
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Cut into list.
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  prev_->next_ = other;
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  prev_ = other;
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(ValidateAsDistinct(other));
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WinXPCondVar::Event* WinXPCondVar::Event::PopFront() {
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(ValidateAsList());
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!IsSingleton());
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return next_->Extract();
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WinXPCondVar::Event* WinXPCondVar::Event::PopBack() {
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(ValidateAsList());
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!IsSingleton());
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return prev_->Extract();
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Methods for use on list elements.
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Accessor method.
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)HANDLE WinXPCondVar::Event::handle() const {
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(ValidateAsItem());
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return handle_;
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Pull an element from a list (if it's in one).
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WinXPCondVar::Event* WinXPCondVar::Event::Extract() {
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(ValidateAsItem());
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!IsSingleton()) {
4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Stitch neighbors together.
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    next_->prev_ = prev_;
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    prev_->next_ = next_;
4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Make extractee into a singleton.
4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    prev_ = next_ = this;
4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(IsSingleton());
4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return this;
4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Method for use on a list element or on a list.
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool WinXPCondVar::Event::IsSingleton() const {
4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(ValidateLinks());
4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return next_ == this;
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Provide pre/post conditions to validate correct manipulations.
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool WinXPCondVar::Event::ValidateAsDistinct(Event* other) const {
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ValidateLinks() && other->ValidateLinks() && (this != other);
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool WinXPCondVar::Event::ValidateAsItem() const {
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (0 != handle_) && ValidateLinks();
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool WinXPCondVar::Event::ValidateAsList() const {
4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (0 == handle_) && ValidateLinks();
4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool WinXPCondVar::Event::ValidateLinks() const {
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Make sure both of our neighbors have links that point back to us.
4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We don't do the O(n) check and traverse the whole loop, and instead only
4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // do a local check to (and returning from) our immediate neighbors.
4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (next_->prev_ == this) && (prev_->next_ == this);
4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)FAQ On WinXPCondVar subtle implementation details:
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)1) What makes this problem subtle?  Please take a look at "Strategies
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)for Implementing POSIX Condition Variables on Win32" by Douglas
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)C. Schmidt and Irfan Pyarali.
4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)http://www.cs.wustl.edu/~schmidt/win32-cv-1.html It includes
4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)discussions of numerous flawed strategies for implementing this
4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)functionality.  I'm not convinced that even the final proposed
4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)implementation has semantics that are as nice as this implementation
4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)(especially with regard to Broadcast() and the impact on threads that
4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)try to Wait() after a Broadcast() has been called, but before all the
4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)original waiting threads have been signaled).
4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)2) Why can't you use a single wait_event for all threads that call
4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Wait()?  See FAQ-question-1, or consider the following: If a single
4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)event were used, then numerous threads calling Wait() could release
4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)their cs locks, and be preempted just before calling
4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)WaitForSingleObject().  If a call to Broadcast() was then presented on
4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)a second thread, it would be impossible to actually signal all
4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)waiting(?) threads.  Some number of SetEvent() calls *could* be made,
4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)but there could be no guarantee that those led to to more than one
4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)signaled thread (SetEvent()'s may be discarded after the first!), and
4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)there could be no guarantee that the SetEvent() calls didn't just
4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)awaken "other" threads that hadn't even started waiting yet (oops).
4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Without any limit on the number of requisite SetEvent() calls, the
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)system would be forced to do many such calls, allowing many new waits
4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)to receive spurious signals.
4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)3) How does this implementation cause spurious signal events?  The
5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)cause in this implementation involves a race between a signal via
5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)time-out and a signal via Signal() or Broadcast().  The series of
5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)actions leading to this are:
5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)a) Timer fires, and a waiting thread exits the line of code:
5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    WaitForSingleObject(waiting_event, max_time.InMilliseconds());
5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)b) That thread (in (a)) is randomly pre-empted after the above line,
5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)leaving the waiting_event reset (unsignaled) and still in the
5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)waiting_list_.
5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)c) A call to Signal() (or Broadcast()) on a second thread proceeds, and
5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)selects the waiting cv_event (identified in step (b)) as the event to revive
5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)via a call to SetEvent().
5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)d) The Signal() method (step c) calls SetEvent() on waiting_event (step b).
5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)e) The waiting cv_event (step b) is now signaled, but no thread is
5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)waiting on it.
5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)f) When that waiting_event (step b) is reused, it will immediately
5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)be signaled (spuriously).
5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)4) Why do you recycle events, and cause spurious signals?  First off,
5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)the spurious events are very rare.  They can only (I think) appear
5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)when the race described in FAQ-question-3 takes place.  This should be
5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)very rare.  Most(?)  uses will involve only timer expiration, or only
5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Signal/Broadcast() actions.  When both are used, it will be rare that
5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)the race will appear, and it would require MANY Wait() and signaling
5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)activities.  If this implementation did not recycle events, then it
5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)would have to create and destroy events for every call to Wait().
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)That allocation/deallocation and associated construction/destruction
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)would be costly (per wait), and would only be a rare benefit (when the
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)race was "lost" and a spurious signal took place). That would be bad
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)(IMO) optimization trade-off.  Finally, such spurious events are
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)allowed by the specification of condition variables (such as
5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)implemented in Vista), and hence it is better if any user accommodates
5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)such spurious events (see usage note in condition_variable.h).
5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)5) Why don't you reset events when you are about to recycle them, or
5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)about to reuse them, so that the spurious signals don't take place?
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)The thread described in FAQ-question-3 step c may be pre-empted for an
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)arbitrary length of time before proceeding to step d.  As a result,
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)the wait_event may actually be re-used *before* step (e) is reached.
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)As a result, calling reset would not help significantly.
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)6) How is it that the callers lock is released atomically with the
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)entry into a wait state?  We commit to the wait activity when we
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)allocate the wait_event for use in a given call to Wait().  This
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)allocation takes place before the caller's lock is released (and
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)actually before our internal_lock_ is released).  That allocation is
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)the defining moment when "the wait state has been entered," as that
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)thread *can* now be signaled by a call to Broadcast() or Signal().
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Hence we actually "commit to wait" before releasing the lock, making
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)the pair effectively atomic.
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)8) Why do you need to lock your data structures during waiting, as the
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)caller is already in possession of a lock?  We need to Acquire() and
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Release() our internal lock during Signal() and Broadcast().  If we tried
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)to use a callers lock for this purpose, we might conflict with their
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)external use of the lock.  For example, the caller may use to consistently
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)hold a lock on one thread while calling Signal() on another, and that would
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)block Signal().
5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)9) Couldn't a more efficient implementation be provided if you
5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)preclude using more than one external lock in conjunction with a
5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)single ConditionVariable instance?  Yes, at least it could be viewed
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)as a simpler API (since you don't have to reiterate the lock argument
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)in each Wait() call).  One of the constructors now takes a specific
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)lock as an argument, and a there are corresponding Wait() calls that
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)don't specify a lock now.  It turns that the resulting implmentation
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)can't be made more efficient, as the internal lock needs to be used by
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Signal() and Broadcast(), to access internal data structures.  As a
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)result, I was not able to utilize the user supplied lock (which is
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)being used by the user elsewhere presumably) to protect the private
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)member access.
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)9) Since you have a second lock, how can be be sure that there is no
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)possible deadlock scenario?  Our internal_lock_ is always the last
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)lock acquired, and the first one released, and hence a deadlock (due
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)to critical section problems) is impossible as a consequence of our
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)lock.
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)10) When doing a Broadcast(), why did you copy all the events into
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)an STL queue, rather than making a linked-loop, and iterating over it?
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)The iterating during Broadcast() is done so outside the protection
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)of the internal lock. As a result, other threads, such as the thread
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)wherein a related event is waiting, could asynchronously manipulate
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)the links around a cv_event.  As a result, the link structure cannot
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)be used outside a lock.  Broadcast() could iterate over waiting
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)events by cycling in-and-out of the protection of the internal_lock,
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)but that appears more expensive than copying the list into an STL
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)stack.
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)11) Why did the lock.h file need to be modified so much for this
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)change?  Central to a Condition Variable is the atomic release of a
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)lock during a Wait().  This places Wait() functionality exactly
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)mid-way between the two classes, Lock and Condition Variable.  Given
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)that there can be nested Acquire()'s of locks, and Wait() had to
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Release() completely a held lock, it was necessary to augment the Lock
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class with a recursion counter. Even more subtle is the fact that the
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)recursion counter (in a Lock) must be protected, as many threads can
6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)access it asynchronously.  As a positive fallout of this, there are
6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)now some DCHECKS to be sure no one Release()s a Lock more than they
6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Acquire()ed it, and there is ifdef'ed functionality that can detect
6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)nested locks (legal under windows, but not under Posix).
6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)12) Why is it that the cv_events removed from list in Broadcast() and Signal()
6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)are not leaked?  How are they recovered??  The cv_events that appear to leak are
6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)taken from the waiting_list_.  For each element in that list, there is currently
6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)a thread in or around the WaitForSingleObject() call of Wait(), and those
6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)threads have references to these otherwise leaked events. They are passed as
6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)arguments to be recycled just aftre returning from WaitForSingleObject().
6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)13) Why did you use a custom container class (the linked list), when STL has
6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)perfectly good containers, such as an STL list?  The STL list, as with any
6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)container, does not guarantee the utility of an iterator across manipulation
6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)(such as insertions and deletions) of the underlying container.  The custom
6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)double-linked-list container provided that assurance.  I don't believe any
6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)combination of STL containers provided the services that were needed at the same
6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)O(1) efficiency as the custom linked list.  The unusual requirement
6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)for the container class is that a reference to an item within a container (an
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)iterator) needed to be maintained across an arbitrary manipulation of the
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)container.  This requirement exposes itself in the Wait() method, where a
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)waiting_event must be selected prior to the WaitForSingleObject(), and then it
6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)must be used as part of recycling to remove the related instance from the
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)waiting_list.  A hash table (STL map) could be used, but I was embarrased to
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)use a complex and relatively low efficiency container when a doubly linked list
6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)provided O(1) performance in all required operations.  Since other operations
6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)to provide performance-and/or-fairness required queue (FIFO) and list (LIFO)
6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)containers, I would also have needed to use an STL list/queue as well as an STL
6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)map.  In the end I decided it would be "fun" to just do it right, and I
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)put so many assertions (DCHECKs) into the container class that it is trivial to
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)code review and validate its correctness.
6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)*/
6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ConditionVariable::ConditionVariable(Lock* user_lock)
6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : impl_(NULL) {
6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static bool use_vista_native_cv = BindVistaCondVarFunctions();
6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (use_vista_native_cv)
6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    impl_= new WinVistaCondVar(user_lock);
6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else
6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    impl_ = new WinXPCondVar(user_lock);
6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ConditionVariable::~ConditionVariable() {
6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delete impl_;
6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ConditionVariable::Wait() {
6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  impl_->Wait();
6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ConditionVariable::TimedWait(const TimeDelta& max_time) {
6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  impl_->TimedWait(max_time);
6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ConditionVariable::Broadcast() {
6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  impl_->Broadcast();
6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ConditionVariable::Signal() {
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  impl_->Signal();
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace base
670