OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/synchronization/condition_variable.h" | 5 #include "base/synchronization/condition_variable.h" |
6 | 6 |
7 #include <windows.h> | 7 #include <windows.h> |
8 #include <stack> | 8 #include <stack> |
9 | 9 |
10 #include "base/compiler_specific.h" | 10 #include "base/compiler_specific.h" |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
12 #include "base/synchronization/lock.h" | 12 #include "base/synchronization/lock.h" |
13 #include "base/time.h" | 13 #include "base/time.h" |
14 | 14 |
| 15 namespace { |
| 16 // We can't use the linker supported delay-load for kernel32 so all this |
| 17 // cruft here is to manually late-bind the needed functions. |
| 18 typedef void (WINAPI *InitializeConditionVariableFn)(PCONDITION_VARIABLE); |
| 19 typedef BOOL (WINAPI *SleepConditionVariableCSFn)(PCONDITION_VARIABLE, |
| 20 PCRITICAL_SECTION, DWORD); |
| 21 typedef void (WINAPI *WakeConditionVariableFn)(PCONDITION_VARIABLE); |
| 22 typedef void (WINAPI *WakeAllConditionVariableFn)(PCONDITION_VARIABLE); |
| 23 |
| 24 InitializeConditionVariableFn initialize_condition_variable_fn; |
| 25 SleepConditionVariableCSFn sleep_condition_variable_fn; |
| 26 WakeConditionVariableFn wake_condition_variable_fn; |
| 27 WakeAllConditionVariableFn wake_all_condition_variable_fn; |
| 28 |
| 29 bool BindVistaCondVarFunctions() { |
| 30 HMODULE kernel32 = GetModuleHandleA("kernel32.dll"); |
| 31 initialize_condition_variable_fn = |
| 32 reinterpret_cast<InitializeConditionVariableFn>( |
| 33 GetProcAddress(kernel32, "InitializeConditionVariable")); |
| 34 if (!initialize_condition_variable_fn) |
| 35 return false; |
| 36 sleep_condition_variable_fn = |
| 37 reinterpret_cast<SleepConditionVariableCSFn>( |
| 38 GetProcAddress(kernel32, "SleepConditionVariableCS")); |
| 39 if (!sleep_condition_variable_fn) |
| 40 return false; |
| 41 wake_condition_variable_fn = |
| 42 reinterpret_cast<WakeConditionVariableFn>( |
| 43 GetProcAddress(kernel32, "WakeConditionVariable")); |
| 44 if (!wake_condition_variable_fn) |
| 45 return false; |
| 46 wake_all_condition_variable_fn = |
| 47 reinterpret_cast<WakeAllConditionVariableFn>( |
| 48 GetProcAddress(kernel32, "WakeAllConditionVariable")); |
| 49 if (!wake_all_condition_variable_fn) |
| 50 return false; |
| 51 return true; |
| 52 } |
| 53 |
| 54 } // namespace. |
| 55 |
15 namespace base { | 56 namespace base { |
16 // Abstract class of the pimpl, idiom. TODO(cpu): create the | 57 // Abstract base class of the pimpl idiom. |
17 // WinVistaCondVar once the WinXPCondVar lands. | |
18 class ConditionVarImpl { | 58 class ConditionVarImpl { |
19 public: | 59 public: |
20 virtual ~ConditionVarImpl() {}; | 60 virtual ~ConditionVarImpl() {}; |
21 virtual void Wait() = 0; | 61 virtual void Wait() = 0; |
22 virtual void TimedWait(const TimeDelta& max_time) = 0; | 62 virtual void TimedWait(const TimeDelta& max_time) = 0; |
23 virtual void Broadcast() = 0; | 63 virtual void Broadcast() = 0; |
24 virtual void Signal() = 0; | 64 virtual void Signal() = 0; |
25 }; | 65 }; |
26 | 66 |
| 67 /////////////////////////////////////////////////////////////////////////////// |
| 68 // Windows Vista and Win7 implementation. |
| 69 /////////////////////////////////////////////////////////////////////////////// |
| 70 |
| 71 class WinVistaCondVar: public ConditionVarImpl { |
| 72 public: |
| 73 WinVistaCondVar(Lock* user_lock); |
| 74 ~WinVistaCondVar() {}; |
| 75 // Overridden from ConditionVarImpl. |
| 76 virtual void Wait() OVERRIDE; |
| 77 virtual void TimedWait(const TimeDelta& max_time) OVERRIDE; |
| 78 virtual void Broadcast() OVERRIDE; |
| 79 virtual void Signal() OVERRIDE; |
| 80 |
| 81 private: |
| 82 base::Lock& user_lock_; |
| 83 CONDITION_VARIABLE cv_; |
| 84 }; |
| 85 |
| 86 WinVistaCondVar::WinVistaCondVar(Lock* user_lock) |
| 87 : user_lock_(*user_lock) { |
| 88 initialize_condition_variable_fn(&cv_); |
| 89 DCHECK(user_lock); |
| 90 } |
| 91 |
| 92 void WinVistaCondVar::Wait() { |
| 93 TimedWait(TimeDelta::FromMilliseconds(INFINITE)); |
| 94 } |
| 95 |
| 96 void WinVistaCondVar::TimedWait(const TimeDelta& max_time) { |
| 97 DWORD timeout = static_cast<DWORD>(max_time.InMilliseconds()); |
| 98 CRITICAL_SECTION* cs = user_lock_.lock_.os_lock(); |
| 99 |
| 100 #if !defined(NDEBUG) |
| 101 user_lock_.CheckHeldAndUnmark(); |
| 102 #endif |
| 103 |
| 104 if (FALSE == sleep_condition_variable_fn(&cv_, cs, timeout)) { |
| 105 DCHECK(GetLastError() != WAIT_TIMEOUT); |
| 106 } |
| 107 |
| 108 #if !defined(NDEBUG) |
| 109 user_lock_.CheckUnheldAndMark(); |
| 110 #endif |
| 111 } |
| 112 |
| 113 void WinVistaCondVar::Broadcast() { |
| 114 wake_all_condition_variable_fn(&cv_); |
| 115 } |
| 116 |
| 117 void WinVistaCondVar::Signal() { |
| 118 wake_condition_variable_fn(&cv_); |
| 119 } |
| 120 |
| 121 /////////////////////////////////////////////////////////////////////////////// |
| 122 // Windows XP implementation. |
| 123 /////////////////////////////////////////////////////////////////////////////// |
| 124 |
27 class WinXPCondVar : public ConditionVarImpl { | 125 class WinXPCondVar : public ConditionVarImpl { |
28 public: | 126 public: |
29 WinXPCondVar(Lock* user_lock); | 127 WinXPCondVar(Lock* user_lock); |
30 ~WinXPCondVar(); | 128 ~WinXPCondVar(); |
31 // Overridden from ConditionVarImpl. | 129 // Overridden from ConditionVarImpl. |
32 virtual void Wait() OVERRIDE; | 130 virtual void Wait() OVERRIDE; |
33 virtual void TimedWait(const TimeDelta& max_time) OVERRIDE; | 131 virtual void TimedWait(const TimeDelta& max_time) OVERRIDE; |
34 virtual void Broadcast() OVERRIDE; | 132 virtual void Broadcast() OVERRIDE; |
35 virtual void Signal() OVERRIDE; | 133 virtual void Signal() OVERRIDE; |
36 | 134 |
(...skipping 493 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
530 provided O(1) performance in all required operations. Since other operations | 628 provided O(1) performance in all required operations. Since other operations |
531 to provide performance-and/or-fairness required queue (FIFO) and list (LIFO) | 629 to provide performance-and/or-fairness required queue (FIFO) and list (LIFO) |
532 containers, I would also have needed to use an STL list/queue as well as an STL | 630 containers, I would also have needed to use an STL list/queue as well as an STL |
533 map. In the end I decided it would be "fun" to just do it right, and I | 631 map. In the end I decided it would be "fun" to just do it right, and I |
534 put so many assertions (DCHECKs) into the container class that it is trivial to | 632 put so many assertions (DCHECKs) into the container class that it is trivial to |
535 code review and validate its correctness. | 633 code review and validate its correctness. |
536 | 634 |
537 */ | 635 */ |
538 | 636 |
539 ConditionVariable::ConditionVariable(Lock* user_lock) | 637 ConditionVariable::ConditionVariable(Lock* user_lock) |
540 : impl_(new WinXPCondVar(user_lock)) { | 638 : impl_(NULL) { |
| 639 static bool use_vista_native_cv = BindVistaCondVarFunctions(); |
| 640 if (use_vista_native_cv) |
| 641 impl_= new WinVistaCondVar(user_lock); |
| 642 else |
| 643 impl_ = new WinXPCondVar(user_lock); |
541 } | 644 } |
542 | 645 |
543 ConditionVariable::~ConditionVariable() { | 646 ConditionVariable::~ConditionVariable() { |
544 delete impl_; | 647 delete impl_; |
545 } | 648 } |
546 | 649 |
547 void ConditionVariable::Wait() { | 650 void ConditionVariable::Wait() { |
548 impl_->Wait(); | 651 impl_->Wait(); |
549 } | 652 } |
550 | 653 |
551 void ConditionVariable::TimedWait(const TimeDelta& max_time) { | 654 void ConditionVariable::TimedWait(const TimeDelta& max_time) { |
552 impl_->TimedWait(max_time); | 655 impl_->TimedWait(max_time); |
553 } | 656 } |
554 | 657 |
555 void ConditionVariable::Broadcast() { | 658 void ConditionVariable::Broadcast() { |
556 impl_->Broadcast(); | 659 impl_->Broadcast(); |
557 } | 660 } |
558 | 661 |
559 void ConditionVariable::Signal() { | 662 void ConditionVariable::Signal() { |
560 impl_->Signal(); | 663 impl_->Signal(); |
561 } | 664 } |
562 | 665 |
563 } // namespace base | 666 } // namespace base |
OLD | NEW |