OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | |
3 * | |
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 | |
6 * tree. An additional intellectual property rights grant can be found | |
7 * in the file PATENTS. All contributing project authors may | |
8 * be found in the AUTHORS file in the root of the source tree. | |
9 */ | |
10 | |
11 // TODO(tommi): Remove completely. As is there is still some code for Windows | |
12 // that relies on ConditionVariableEventWin, but code has been removed on other | |
13 // platforms. | |
14 #if defined(WEBRTC_WIN) | |
15 | |
16 #include "webrtc/base/platform_thread.h" | |
17 #include "webrtc/base/timeutils.h" | |
18 #include "webrtc/system_wrappers/include/critical_section_wrapper.h" | |
19 #include "webrtc/system_wrappers/source/condition_variable_event_win.h" | |
20 #include "webrtc/test/gtest.h" | |
21 | |
22 namespace webrtc { | |
23 | |
24 namespace { | |
25 | |
26 const int kLongWaitMs = 100 * 1000; // A long time in testing terms | |
27 const int kShortWaitMs = 2 * 1000; // Long enough for process switches to happen | |
28 const int kVeryShortWaitMs = 20; // Used when we want a timeout | |
29 | |
30 // A Baton is one possible control structure one can build using | |
31 // conditional variables. | |
32 // A Baton is always held by one and only one active thread - unlike | |
33 // a lock, it can never be free. | |
34 // One can pass it or grab it - both calls have timeouts. | |
35 // Note - a production tool would guard against passing it without | |
36 // grabbing it first. This one is for testing, so it doesn't. | |
37 class Baton { | |
38 public: | |
39 Baton() | |
40 : being_passed_(false), | |
41 pass_count_(0) { | |
42 InitializeCriticalSection(&crit_sect_); | |
43 } | |
44 | |
45 ~Baton() { | |
46 DeleteCriticalSection(&crit_sect_); | |
47 } | |
48 | |
49 // Pass the baton. Returns false if baton is not picked up in |max_msecs|. | |
50 // Only one process can pass at the same time; this property is | |
51 // ensured by the |giver_sect_| lock. | |
52 bool Pass(uint32_t max_msecs) { | |
53 CriticalSectionScoped cs_giver(&giver_sect_); | |
54 EnterCriticalSection(&crit_sect_); | |
55 SignalBatonAvailable(); | |
56 const bool result = TakeBatonIfStillFree(max_msecs); | |
57 if (result) { | |
58 ++pass_count_; | |
59 } | |
60 LeaveCriticalSection(&crit_sect_); | |
61 return result; | |
62 } | |
63 | |
64 // Grab the baton. Returns false if baton is not passed. | |
65 bool Grab(uint32_t max_msecs) { | |
66 EnterCriticalSection(&crit_sect_); | |
67 bool ret = WaitUntilBatonOffered(max_msecs); | |
68 LeaveCriticalSection(&crit_sect_); | |
69 return ret; | |
70 } | |
71 | |
72 int PassCount() { | |
73 // We don't allow polling PassCount() during a Pass()-call since there is | |
74 // no guarantee that |pass_count_| is incremented until the Pass()-call | |
75 // finishes. I.e. the Grab()-call may finish before |pass_count_| has been | |
76 // incremented. | |
77 // Thus, this function waits on giver_sect_. | |
78 CriticalSectionScoped cs(&giver_sect_); | |
79 return pass_count_; | |
80 } | |
81 | |
82 private: | |
83 // Wait/Signal forms a classical semaphore on |being_passed_|. | |
84 // These functions must be called with crit_sect_ held. | |
85 bool WaitUntilBatonOffered(int timeout_ms) { | |
86 while (!being_passed_) { | |
87 if (!cond_var_.SleepCS(&crit_sect_, timeout_ms)) { | |
88 return false; | |
89 } | |
90 } | |
91 being_passed_ = false; | |
92 cond_var_.Wake(); | |
93 return true; | |
94 } | |
95 | |
96 void SignalBatonAvailable() { | |
97 assert(!being_passed_); | |
98 being_passed_ = true; | |
99 cond_var_.Wake(); | |
100 } | |
101 | |
102 // Timeout extension: Wait for a limited time for someone else to | |
103 // take it, and take it if it's not taken. | |
104 // Returns true if resource is taken by someone else, false | |
105 // if it is taken back by the caller. | |
106 // This function must be called with both |giver_sect_| and | |
107 // |crit_sect_| held. | |
108 bool TakeBatonIfStillFree(int timeout_ms) { | |
109 bool not_timeout = true; | |
110 while (being_passed_ && not_timeout) { | |
111 not_timeout = cond_var_.SleepCS(&crit_sect_, timeout_ms); | |
112 // If we're woken up while variable is still held, we may have | |
113 // gotten a wakeup destined for a grabber thread. | |
114 // This situation is not treated specially here. | |
115 } | |
116 if (!being_passed_) | |
117 return true; | |
118 assert(!not_timeout); | |
119 being_passed_ = false; | |
120 return false; | |
121 } | |
122 | |
123 // Lock that ensures that there is only one thread in the active | |
124 // part of Pass() at a time. | |
125 // |giver_sect_| must always be acquired before |cond_var_|. | |
126 CriticalSectionWrapper giver_sect_; | |
127 // Lock that protects |being_passed_|. | |
128 CRITICAL_SECTION crit_sect_; | |
129 ConditionVariableEventWin cond_var_; | |
130 bool being_passed_; | |
131 // Statistics information: Number of successfull passes. | |
132 int pass_count_; | |
133 }; | |
134 | |
135 // Function that waits on a Baton, and passes it right back. | |
136 // We expect these calls never to time out. | |
137 bool WaitingRunFunction(void* obj) { | |
138 Baton* the_baton = static_cast<Baton*> (obj); | |
139 EXPECT_TRUE(the_baton->Grab(kLongWaitMs)); | |
140 EXPECT_TRUE(the_baton->Pass(kLongWaitMs)); | |
141 return true; | |
142 } | |
143 | |
144 class CondVarTest : public ::testing::Test { | |
145 public: | |
146 CondVarTest() : thread_(&WaitingRunFunction, &baton_, "CondVarTest") {} | |
147 | |
148 virtual void SetUp() { | |
149 thread_.Start(); | |
150 } | |
151 | |
152 virtual void TearDown() { | |
153 // We have to wake the thread in order to make it obey the stop order. | |
154 // But we don't know if the thread has completed the run function, so | |
155 // we don't know if it will exit before or after the Pass. | |
156 // Thus, we need to pin it down inside its Run function (between Grab | |
157 // and Pass). | |
158 ASSERT_TRUE(baton_.Pass(kShortWaitMs)); | |
159 ASSERT_TRUE(baton_.Grab(kShortWaitMs)); | |
160 thread_.Stop(); | |
161 } | |
162 | |
163 protected: | |
164 Baton baton_; | |
165 | |
166 private: | |
167 rtc::PlatformThread thread_; | |
168 }; | |
169 | |
170 // The SetUp and TearDown functions use condition variables. | |
171 // This test verifies those pieces in isolation. | |
172 // Disabled due to flakiness. See bug 4262 for details. | |
173 TEST_F(CondVarTest, DISABLED_InitFunctionsWork) { | |
174 // All relevant asserts are in the SetUp and TearDown functions. | |
175 } | |
176 | |
177 // This test verifies that one can use the baton multiple times. | |
178 TEST_F(CondVarTest, DISABLED_PassBatonMultipleTimes) { | |
179 const int kNumberOfRounds = 2; | |
180 for (int i = 0; i < kNumberOfRounds; ++i) { | |
181 ASSERT_TRUE(baton_.Pass(kShortWaitMs)); | |
182 ASSERT_TRUE(baton_.Grab(kShortWaitMs)); | |
183 } | |
184 EXPECT_EQ(2 * kNumberOfRounds, baton_.PassCount()); | |
185 } | |
186 | |
187 TEST(CondVarWaitTest, WaitingWaits) { | |
188 CRITICAL_SECTION crit_sect; | |
189 InitializeCriticalSection(&crit_sect); | |
190 ConditionVariableEventWin cond_var; | |
191 EnterCriticalSection(&crit_sect); | |
192 int64_t start_ms = rtc::TimeMillis(); | |
193 EXPECT_FALSE(cond_var.SleepCS(&crit_sect, kVeryShortWaitMs)); | |
194 int64_t end_ms = rtc::TimeMillis(); | |
195 EXPECT_LE(start_ms + kVeryShortWaitMs, end_ms) | |
196 << "actual elapsed:" << end_ms - start_ms; | |
197 LeaveCriticalSection(&crit_sect); | |
198 DeleteCriticalSection(&crit_sect); | |
199 } | |
200 | |
201 } // anonymous namespace | |
202 | |
203 } // namespace webrtc | |
204 | |
205 #endif // defined(WEBRTC_WIN) | |
OLD | NEW |