OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include "webrtc/system_wrappers/include/condition_variable_wrapper.h" | |
12 | |
13 // TODO(tommi): Remove completely. As is there is still some code for Windows | 11 // TODO(tommi): Remove completely. As is there is still some code for Windows |
14 // that relies on ConditionVariableWrapper, but code has been removed on other | 12 // that relies on ConditionVariableEventWin, but code has been removed on other |
15 // platforms. | 13 // platforms. |
16 #if defined(WEBRTC_WIN) | 14 #if defined(WEBRTC_WIN) |
17 | 15 |
| 16 #include "webrtc/system_wrappers/source/condition_variable_event_win.h" |
| 17 |
18 #include "testing/gtest/include/gtest/gtest.h" | 18 #include "testing/gtest/include/gtest/gtest.h" |
19 #include "webrtc/base/platform_thread.h" | 19 #include "webrtc/base/platform_thread.h" |
20 #include "webrtc/base/scoped_ptr.h" | 20 #include "webrtc/base/scoped_ptr.h" |
21 #include "webrtc/system_wrappers/include/critical_section_wrapper.h" | 21 #include "webrtc/system_wrappers/include/critical_section_wrapper.h" |
22 #include "webrtc/system_wrappers/include/tick_util.h" | 22 #include "webrtc/system_wrappers/include/tick_util.h" |
23 #include "webrtc/system_wrappers/include/trace.h" | 23 #include "webrtc/system_wrappers/include/trace.h" |
24 | 24 |
25 namespace webrtc { | 25 namespace webrtc { |
26 | 26 |
27 namespace { | 27 namespace { |
28 | 28 |
29 const int kLongWaitMs = 100 * 1000; // A long time in testing terms | 29 const int kLongWaitMs = 100 * 1000; // A long time in testing terms |
30 const int kShortWaitMs = 2 * 1000; // Long enough for process switches to happen | 30 const int kShortWaitMs = 2 * 1000; // Long enough for process switches to happen |
31 const int kVeryShortWaitMs = 20; // Used when we want a timeout | 31 const int kVeryShortWaitMs = 20; // Used when we want a timeout |
32 | 32 |
33 // A Baton is one possible control structure one can build using | 33 // A Baton is one possible control structure one can build using |
34 // conditional variables. | 34 // conditional variables. |
35 // A Baton is always held by one and only one active thread - unlike | 35 // A Baton is always held by one and only one active thread - unlike |
36 // a lock, it can never be free. | 36 // a lock, it can never be free. |
37 // One can pass it or grab it - both calls have timeouts. | 37 // One can pass it or grab it - both calls have timeouts. |
38 // Note - a production tool would guard against passing it without | 38 // Note - a production tool would guard against passing it without |
39 // grabbing it first. This one is for testing, so it doesn't. | 39 // grabbing it first. This one is for testing, so it doesn't. |
40 class Baton { | 40 class Baton { |
41 public: | 41 public: |
42 Baton() | 42 Baton() |
43 : giver_sect_(CriticalSectionWrapper::CreateCriticalSection()), | 43 : being_passed_(false), |
44 crit_sect_(CriticalSectionWrapper::CreateCriticalSection()), | |
45 cond_var_(ConditionVariableWrapper::CreateConditionVariable()), | |
46 being_passed_(false), | |
47 pass_count_(0) { | 44 pass_count_(0) { |
| 45 InitializeCriticalSection(&crit_sect_); |
48 } | 46 } |
49 | 47 |
50 ~Baton() { | 48 ~Baton() { |
51 delete giver_sect_; | 49 DeleteCriticalSection(&crit_sect_); |
52 delete crit_sect_; | |
53 delete cond_var_; | |
54 } | 50 } |
55 | 51 |
56 // Pass the baton. Returns false if baton is not picked up in |max_msecs|. | 52 // Pass the baton. Returns false if baton is not picked up in |max_msecs|. |
57 // Only one process can pass at the same time; this property is | 53 // Only one process can pass at the same time; this property is |
58 // ensured by the |giver_sect_| lock. | 54 // ensured by the |giver_sect_| lock. |
59 bool Pass(uint32_t max_msecs) { | 55 bool Pass(uint32_t max_msecs) { |
60 CriticalSectionScoped cs_giver(giver_sect_); | 56 CriticalSectionScoped cs_giver(&giver_sect_); |
61 CriticalSectionScoped cs(crit_sect_); | 57 EnterCriticalSection(&crit_sect_); |
62 SignalBatonAvailable(); | 58 SignalBatonAvailable(); |
63 const bool result = TakeBatonIfStillFree(max_msecs); | 59 const bool result = TakeBatonIfStillFree(max_msecs); |
64 if (result) { | 60 if (result) { |
65 ++pass_count_; | 61 ++pass_count_; |
66 } | 62 } |
| 63 LeaveCriticalSection(&crit_sect_); |
67 return result; | 64 return result; |
68 } | 65 } |
69 | 66 |
70 // Grab the baton. Returns false if baton is not passed. | 67 // Grab the baton. Returns false if baton is not passed. |
71 bool Grab(uint32_t max_msecs) { | 68 bool Grab(uint32_t max_msecs) { |
72 CriticalSectionScoped cs(crit_sect_); | 69 EnterCriticalSection(&crit_sect_); |
73 return WaitUntilBatonOffered(max_msecs); | 70 bool ret = WaitUntilBatonOffered(max_msecs); |
| 71 LeaveCriticalSection(&crit_sect_); |
| 72 return ret; |
74 } | 73 } |
75 | 74 |
76 int PassCount() { | 75 int PassCount() { |
77 // We don't allow polling PassCount() during a Pass()-call since there is | 76 // We don't allow polling PassCount() during a Pass()-call since there is |
78 // no guarantee that |pass_count_| is incremented until the Pass()-call | 77 // no guarantee that |pass_count_| is incremented until the Pass()-call |
79 // finishes. I.e. the Grab()-call may finish before |pass_count_| has been | 78 // finishes. I.e. the Grab()-call may finish before |pass_count_| has been |
80 // incremented. | 79 // incremented. |
81 // Thus, this function waits on giver_sect_. | 80 // Thus, this function waits on giver_sect_. |
82 CriticalSectionScoped cs(giver_sect_); | 81 CriticalSectionScoped cs(&giver_sect_); |
83 return pass_count_; | 82 return pass_count_; |
84 } | 83 } |
85 | 84 |
86 private: | 85 private: |
87 // Wait/Signal forms a classical semaphore on |being_passed_|. | 86 // Wait/Signal forms a classical semaphore on |being_passed_|. |
88 // These functions must be called with crit_sect_ held. | 87 // These functions must be called with crit_sect_ held. |
89 bool WaitUntilBatonOffered(int timeout_ms) { | 88 bool WaitUntilBatonOffered(int timeout_ms) { |
90 while (!being_passed_) { | 89 while (!being_passed_) { |
91 if (!cond_var_->SleepCS(*crit_sect_, timeout_ms)) { | 90 if (!cond_var_.SleepCS(&crit_sect_, timeout_ms)) { |
92 return false; | 91 return false; |
93 } | 92 } |
94 } | 93 } |
95 being_passed_ = false; | 94 being_passed_ = false; |
96 cond_var_->Wake(); | 95 cond_var_.Wake(); |
97 return true; | 96 return true; |
98 } | 97 } |
99 | 98 |
100 void SignalBatonAvailable() { | 99 void SignalBatonAvailable() { |
101 assert(!being_passed_); | 100 assert(!being_passed_); |
102 being_passed_ = true; | 101 being_passed_ = true; |
103 cond_var_->Wake(); | 102 cond_var_.Wake(); |
104 } | 103 } |
105 | 104 |
106 // Timeout extension: Wait for a limited time for someone else to | 105 // Timeout extension: Wait for a limited time for someone else to |
107 // take it, and take it if it's not taken. | 106 // take it, and take it if it's not taken. |
108 // Returns true if resource is taken by someone else, false | 107 // Returns true if resource is taken by someone else, false |
109 // if it is taken back by the caller. | 108 // if it is taken back by the caller. |
110 // This function must be called with both |giver_sect_| and | 109 // This function must be called with both |giver_sect_| and |
111 // |crit_sect_| held. | 110 // |crit_sect_| held. |
112 bool TakeBatonIfStillFree(int timeout_ms) { | 111 bool TakeBatonIfStillFree(int timeout_ms) { |
113 bool not_timeout = true; | 112 bool not_timeout = true; |
114 while (being_passed_ && not_timeout) { | 113 while (being_passed_ && not_timeout) { |
115 not_timeout = cond_var_->SleepCS(*crit_sect_, timeout_ms); | 114 not_timeout = cond_var_.SleepCS(&crit_sect_, timeout_ms); |
116 // If we're woken up while variable is still held, we may have | 115 // If we're woken up while variable is still held, we may have |
117 // gotten a wakeup destined for a grabber thread. | 116 // gotten a wakeup destined for a grabber thread. |
118 // This situation is not treated specially here. | 117 // This situation is not treated specially here. |
119 } | 118 } |
120 if (!being_passed_) { | 119 if (!being_passed_) |
121 return true; | 120 return true; |
122 } else { | 121 assert(!not_timeout); |
123 assert(!not_timeout); | 122 being_passed_ = false; |
124 being_passed_ = false; | 123 return false; |
125 return false; | |
126 } | |
127 } | 124 } |
128 | 125 |
129 // Lock that ensures that there is only one thread in the active | 126 // Lock that ensures that there is only one thread in the active |
130 // part of Pass() at a time. | 127 // part of Pass() at a time. |
131 // |giver_sect_| must always be acquired before |cond_var_|. | 128 // |giver_sect_| must always be acquired before |cond_var_|. |
132 CriticalSectionWrapper* giver_sect_; | 129 CriticalSectionWrapper giver_sect_; |
133 // Lock that protects |being_passed_|. | 130 // Lock that protects |being_passed_|. |
134 CriticalSectionWrapper* crit_sect_; | 131 CRITICAL_SECTION crit_sect_; |
135 ConditionVariableWrapper* cond_var_; | 132 ConditionVariableEventWin cond_var_; |
136 bool being_passed_; | 133 bool being_passed_; |
137 // Statistics information: Number of successfull passes. | 134 // Statistics information: Number of successfull passes. |
138 int pass_count_; | 135 int pass_count_; |
139 }; | 136 }; |
140 | 137 |
141 // Function that waits on a Baton, and passes it right back. | 138 // Function that waits on a Baton, and passes it right back. |
142 // We expect these calls never to time out. | 139 // We expect these calls never to time out. |
143 bool WaitingRunFunction(void* obj) { | 140 bool WaitingRunFunction(void* obj) { |
144 Baton* the_baton = static_cast<Baton*> (obj); | 141 Baton* the_baton = static_cast<Baton*> (obj); |
145 EXPECT_TRUE(the_baton->Grab(kLongWaitMs)); | 142 EXPECT_TRUE(the_baton->Grab(kLongWaitMs)); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
184 TEST_F(CondVarTest, DISABLED_PassBatonMultipleTimes) { | 181 TEST_F(CondVarTest, DISABLED_PassBatonMultipleTimes) { |
185 const int kNumberOfRounds = 2; | 182 const int kNumberOfRounds = 2; |
186 for (int i = 0; i < kNumberOfRounds; ++i) { | 183 for (int i = 0; i < kNumberOfRounds; ++i) { |
187 ASSERT_TRUE(baton_.Pass(kShortWaitMs)); | 184 ASSERT_TRUE(baton_.Pass(kShortWaitMs)); |
188 ASSERT_TRUE(baton_.Grab(kShortWaitMs)); | 185 ASSERT_TRUE(baton_.Grab(kShortWaitMs)); |
189 } | 186 } |
190 EXPECT_EQ(2 * kNumberOfRounds, baton_.PassCount()); | 187 EXPECT_EQ(2 * kNumberOfRounds, baton_.PassCount()); |
191 } | 188 } |
192 | 189 |
193 TEST(CondVarWaitTest, WaitingWaits) { | 190 TEST(CondVarWaitTest, WaitingWaits) { |
194 rtc::scoped_ptr<CriticalSectionWrapper> crit_sect( | 191 CRITICAL_SECTION crit_sect; |
195 CriticalSectionWrapper::CreateCriticalSection()); | 192 InitializeCriticalSection(&crit_sect); |
196 rtc::scoped_ptr<ConditionVariableWrapper> cond_var( | 193 ConditionVariableEventWin cond_var; |
197 ConditionVariableWrapper::CreateConditionVariable()); | 194 EnterCriticalSection(&crit_sect); |
198 CriticalSectionScoped cs(crit_sect.get()); | |
199 int64_t start_ms = TickTime::MillisecondTimestamp(); | 195 int64_t start_ms = TickTime::MillisecondTimestamp(); |
200 EXPECT_FALSE(cond_var->SleepCS(*(crit_sect), kVeryShortWaitMs)); | 196 EXPECT_FALSE(cond_var.SleepCS(&crit_sect, kVeryShortWaitMs)); |
201 int64_t end_ms = TickTime::MillisecondTimestamp(); | 197 int64_t end_ms = TickTime::MillisecondTimestamp(); |
202 EXPECT_LE(start_ms + kVeryShortWaitMs, end_ms) | 198 EXPECT_LE(start_ms + kVeryShortWaitMs, end_ms) |
203 << "actual elapsed:" << end_ms - start_ms; | 199 << "actual elapsed:" << end_ms - start_ms; |
| 200 LeaveCriticalSection(&crit_sect); |
| 201 DeleteCriticalSection(&crit_sect); |
204 } | 202 } |
205 | 203 |
206 } // anonymous namespace | 204 } // anonymous namespace |
207 | 205 |
208 } // namespace webrtc | 206 } // namespace webrtc |
209 | 207 |
210 #endif // defined(WEBRTC_WIN) | 208 #endif // defined(WEBRTC_WIN) |
OLD | NEW |