summaryrefslogtreecommitdiffstats
path: root/base/synchronization/condition_variable_win.cc
diff options
context:
space:
mode:
Diffstat (limited to 'base/synchronization/condition_variable_win.cc')
-rw-r--r--base/synchronization/condition_variable_win.cc109
1 files changed, 106 insertions, 3 deletions
diff --git a/base/synchronization/condition_variable_win.cc b/base/synchronization/condition_variable_win.cc
index cd74120..4f6827f 100644
--- a/base/synchronization/condition_variable_win.cc
+++ b/base/synchronization/condition_variable_win.cc
@@ -12,9 +12,49 @@
#include "base/synchronization/lock.h"
#include "base/time.h"
+namespace {
+// We can't use the linker supported delay-load for kernel32 so all this
+// cruft here is to manually late-bind the needed functions.
+typedef void (WINAPI *InitializeConditionVariableFn)(PCONDITION_VARIABLE);
+typedef BOOL (WINAPI *SleepConditionVariableCSFn)(PCONDITION_VARIABLE,
+ PCRITICAL_SECTION, DWORD);
+typedef void (WINAPI *WakeConditionVariableFn)(PCONDITION_VARIABLE);
+typedef void (WINAPI *WakeAllConditionVariableFn)(PCONDITION_VARIABLE);
+
+InitializeConditionVariableFn initialize_condition_variable_fn;
+SleepConditionVariableCSFn sleep_condition_variable_fn;
+WakeConditionVariableFn wake_condition_variable_fn;
+WakeAllConditionVariableFn wake_all_condition_variable_fn;
+
+bool BindVistaCondVarFunctions() {
+ HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
+ initialize_condition_variable_fn =
+ reinterpret_cast<InitializeConditionVariableFn>(
+ GetProcAddress(kernel32, "InitializeConditionVariable"));
+ if (!initialize_condition_variable_fn)
+ return false;
+ sleep_condition_variable_fn =
+ reinterpret_cast<SleepConditionVariableCSFn>(
+ GetProcAddress(kernel32, "SleepConditionVariableCS"));
+ if (!sleep_condition_variable_fn)
+ return false;
+ wake_condition_variable_fn =
+ reinterpret_cast<WakeConditionVariableFn>(
+ GetProcAddress(kernel32, "WakeConditionVariable"));
+ if (!wake_condition_variable_fn)
+ return false;
+ wake_all_condition_variable_fn =
+ reinterpret_cast<WakeAllConditionVariableFn>(
+ GetProcAddress(kernel32, "WakeAllConditionVariable"));
+ if (!wake_all_condition_variable_fn)
+ return false;
+ return true;
+}
+
+} // namespace.
+
namespace base {
-// Abstract class of the pimpl, idiom. TODO(cpu): create the
-// WinVistaCondVar once the WinXPCondVar lands.
+// Abstract base class of the pimpl idiom.
class ConditionVarImpl {
public:
virtual ~ConditionVarImpl() {};
@@ -24,6 +64,64 @@ class ConditionVarImpl {
virtual void Signal() = 0;
};
+///////////////////////////////////////////////////////////////////////////////
+// Windows Vista and Win7 implementation.
+///////////////////////////////////////////////////////////////////////////////
+
+class WinVistaCondVar: public ConditionVarImpl {
+ public:
+ WinVistaCondVar(Lock* user_lock);
+ ~WinVistaCondVar() {};
+ // Overridden from ConditionVarImpl.
+ virtual void Wait() OVERRIDE;
+ virtual void TimedWait(const TimeDelta& max_time) OVERRIDE;
+ virtual void Broadcast() OVERRIDE;
+ virtual void Signal() OVERRIDE;
+
+ private:
+ base::Lock& user_lock_;
+ CONDITION_VARIABLE cv_;
+};
+
+WinVistaCondVar::WinVistaCondVar(Lock* user_lock)
+ : user_lock_(*user_lock) {
+ initialize_condition_variable_fn(&cv_);
+ DCHECK(user_lock);
+}
+
+void WinVistaCondVar::Wait() {
+ TimedWait(TimeDelta::FromMilliseconds(INFINITE));
+}
+
+void WinVistaCondVar::TimedWait(const TimeDelta& max_time) {
+ DWORD timeout = static_cast<DWORD>(max_time.InMilliseconds());
+ CRITICAL_SECTION* cs = user_lock_.lock_.os_lock();
+
+#if !defined(NDEBUG)
+ user_lock_.CheckHeldAndUnmark();
+#endif
+
+ if (FALSE == sleep_condition_variable_fn(&cv_, cs, timeout)) {
+ DCHECK(GetLastError() != WAIT_TIMEOUT);
+ }
+
+#if !defined(NDEBUG)
+ user_lock_.CheckUnheldAndMark();
+#endif
+}
+
+void WinVistaCondVar::Broadcast() {
+ wake_all_condition_variable_fn(&cv_);
+}
+
+void WinVistaCondVar::Signal() {
+ wake_condition_variable_fn(&cv_);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Windows XP implementation.
+///////////////////////////////////////////////////////////////////////////////
+
class WinXPCondVar : public ConditionVarImpl {
public:
WinXPCondVar(Lock* user_lock);
@@ -537,7 +635,12 @@ code review and validate its correctness.
*/
ConditionVariable::ConditionVariable(Lock* user_lock)
- : impl_(new WinXPCondVar(user_lock)) {
+ : impl_(NULL) {
+ static bool use_vista_native_cv = BindVistaCondVarFunctions();
+ if (use_vista_native_cv)
+ impl_= new WinVistaCondVar(user_lock);
+ else
+ impl_ = new WinXPCondVar(user_lock);
}
ConditionVariable::~ConditionVariable() {