blob: 2e873dca1687e924d653d79d401da67ecf1ea966 [file] [log] [blame]
hta@webrtc.org72e3a892012-06-19 13:49:48 +00001/*
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
Henrik Kjellander98f53512015-10-28 18:17:40 +010011#include "webrtc/system_wrappers/include/condition_variable_wrapper.h"
hta@webrtc.org72e3a892012-06-19 13:49:48 +000012
tommicd255cc2016-01-19 13:13:14 -080013// 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
15// platforms.
16#if defined(WEBRTC_WIN)
17
pbos@webrtc.orgacaf3a12013-05-27 15:07:45 +000018#include "testing/gtest/include/gtest/gtest.h"
pbos12411ef2015-11-23 14:47:56 -080019#include "webrtc/base/platform_thread.h"
hta3866c4f2015-10-20 09:31:01 -070020#include "webrtc/base/scoped_ptr.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010021#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010022#include "webrtc/system_wrappers/include/tick_util.h"
23#include "webrtc/system_wrappers/include/trace.h"
hta@webrtc.org72e3a892012-06-19 13:49:48 +000024
25namespace webrtc {
26
27namespace {
28
phoglund@webrtc.orga36d75a2012-11-14 09:55:04 +000029const int kLongWaitMs = 100 * 1000; // A long time in testing terms
30const int kShortWaitMs = 2 * 1000; // Long enough for process switches to happen
hta3866c4f2015-10-20 09:31:01 -070031const int kVeryShortWaitMs = 20; // Used when we want a timeout
hta@webrtc.org72e3a892012-06-19 13:49:48 +000032
hta@webrtc.org72e3a892012-06-19 13:49:48 +000033// A Baton is one possible control structure one can build using
34// conditional variables.
35// A Baton is always held by one and only one active thread - unlike
36// a lock, it can never be free.
37// One can pass it or grab it - both calls have timeouts.
38// Note - a production tool would guard against passing it without
39// grabbing it first. This one is for testing, so it doesn't.
40class Baton {
41 public:
42 Baton()
43 : giver_sect_(CriticalSectionWrapper::CreateCriticalSection()),
44 crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
45 cond_var_(ConditionVariableWrapper::CreateConditionVariable()),
46 being_passed_(false),
47 pass_count_(0) {
48 }
49
50 ~Baton() {
51 delete giver_sect_;
52 delete crit_sect_;
53 delete cond_var_;
54 }
55
56 // 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
58 // ensured by the |giver_sect_| lock.
pbos@webrtc.org046deb92013-04-09 09:06:11 +000059 bool Pass(uint32_t max_msecs) {
hta@webrtc.org72e3a892012-06-19 13:49:48 +000060 CriticalSectionScoped cs_giver(giver_sect_);
hta@webrtc.org72e3a892012-06-19 13:49:48 +000061 CriticalSectionScoped cs(crit_sect_);
62 SignalBatonAvailable();
63 const bool result = TakeBatonIfStillFree(max_msecs);
64 if (result) {
65 ++pass_count_;
hta@webrtc.org72e3a892012-06-19 13:49:48 +000066 }
67 return result;
68 }
69
70 // Grab the baton. Returns false if baton is not passed.
pbos@webrtc.org046deb92013-04-09 09:06:11 +000071 bool Grab(uint32_t max_msecs) {
hta@webrtc.org72e3a892012-06-19 13:49:48 +000072 CriticalSectionScoped cs(crit_sect_);
73 return WaitUntilBatonOffered(max_msecs);
74 }
75
76 int PassCount() {
77 // 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
79 // finishes. I.e. the Grab()-call may finish before |pass_count_| has been
80 // incremented.
81 // Thus, this function waits on giver_sect_.
82 CriticalSectionScoped cs(giver_sect_);
83 return pass_count_;
84 }
85
86 private:
87 // Wait/Signal forms a classical semaphore on |being_passed_|.
88 // These functions must be called with crit_sect_ held.
89 bool WaitUntilBatonOffered(int timeout_ms) {
90 while (!being_passed_) {
hta@webrtc.org72e3a892012-06-19 13:49:48 +000091 if (!cond_var_->SleepCS(*crit_sect_, timeout_ms)) {
hta@webrtc.org72e3a892012-06-19 13:49:48 +000092 return false;
93 }
94 }
95 being_passed_ = false;
96 cond_var_->Wake();
97 return true;
98 }
99
100 void SignalBatonAvailable() {
101 assert(!being_passed_);
102 being_passed_ = true;
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000103 cond_var_->Wake();
104 }
105
106 // Timeout extension: Wait for a limited time for someone else to
107 // take it, and take it if it's not taken.
108 // Returns true if resource is taken by someone else, false
109 // if it is taken back by the caller.
110 // This function must be called with both |giver_sect_| and
111 // |crit_sect_| held.
112 bool TakeBatonIfStillFree(int timeout_ms) {
113 bool not_timeout = true;
114 while (being_passed_ && not_timeout) {
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000115 not_timeout = cond_var_->SleepCS(*crit_sect_, timeout_ms);
116 // If we're woken up while variable is still held, we may have
117 // gotten a wakeup destined for a grabber thread.
118 // This situation is not treated specially here.
119 }
120 if (!being_passed_) {
121 return true;
122 } else {
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000123 assert(!not_timeout);
124 being_passed_ = false;
125 return false;
126 }
127 }
128
129 // Lock that ensures that there is only one thread in the active
130 // part of Pass() at a time.
131 // |giver_sect_| must always be acquired before |cond_var_|.
132 CriticalSectionWrapper* giver_sect_;
133 // Lock that protects |being_passed_|.
134 CriticalSectionWrapper* crit_sect_;
135 ConditionVariableWrapper* cond_var_;
136 bool being_passed_;
137 // Statistics information: Number of successfull passes.
138 int pass_count_;
139};
140
141// Function that waits on a Baton, and passes it right back.
142// We expect these calls never to time out.
143bool WaitingRunFunction(void* obj) {
andrew@webrtc.org50419b02012-11-14 19:07:54 +0000144 Baton* the_baton = static_cast<Baton*> (obj);
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000145 EXPECT_TRUE(the_baton->Grab(kLongWaitMs));
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000146 EXPECT_TRUE(the_baton->Pass(kLongWaitMs));
147 return true;
148}
149
150class CondVarTest : public ::testing::Test {
151 public:
Peter Boström8c38e8b2015-11-26 17:45:47 +0100152 CondVarTest() : thread_(&WaitingRunFunction, &baton_, "CondVarTest") {}
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000153
154 virtual void SetUp() {
Peter Boström8c38e8b2015-11-26 17:45:47 +0100155 thread_.Start();
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000156 }
157
158 virtual void TearDown() {
159 // We have to wake the thread in order to make it obey the stop order.
160 // But we don't know if the thread has completed the run function, so
161 // we don't know if it will exit before or after the Pass.
162 // Thus, we need to pin it down inside its Run function (between Grab
163 // and Pass).
164 ASSERT_TRUE(baton_.Pass(kShortWaitMs));
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000165 ASSERT_TRUE(baton_.Grab(kShortWaitMs));
Peter Boström8c38e8b2015-11-26 17:45:47 +0100166 thread_.Stop();
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000167 }
168
169 protected:
170 Baton baton_;
171
172 private:
Peter Boström8c38e8b2015-11-26 17:45:47 +0100173 rtc::PlatformThread thread_;
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000174};
175
176// The SetUp and TearDown functions use condition variables.
177// This test verifies those pieces in isolation.
tommi@webrtc.org5d32f432015-02-05 06:25:35 +0000178// Disabled due to flakiness. See bug 4262 for details.
179TEST_F(CondVarTest, DISABLED_InitFunctionsWork) {
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000180 // All relevant asserts are in the SetUp and TearDown functions.
181}
182
183// This test verifies that one can use the baton multiple times.
bjornv@webrtc.orgdc096f22015-02-04 09:14:14 +0000184TEST_F(CondVarTest, DISABLED_PassBatonMultipleTimes) {
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000185 const int kNumberOfRounds = 2;
186 for (int i = 0; i < kNumberOfRounds; ++i) {
187 ASSERT_TRUE(baton_.Pass(kShortWaitMs));
188 ASSERT_TRUE(baton_.Grab(kShortWaitMs));
189 }
phoglund@webrtc.orga36d75a2012-11-14 09:55:04 +0000190 EXPECT_EQ(2 * kNumberOfRounds, baton_.PassCount());
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000191}
192
hta3866c4f2015-10-20 09:31:01 -0700193TEST(CondVarWaitTest, WaitingWaits) {
194 rtc::scoped_ptr<CriticalSectionWrapper> crit_sect(
195 CriticalSectionWrapper::CreateCriticalSection());
196 rtc::scoped_ptr<ConditionVariableWrapper> cond_var(
197 ConditionVariableWrapper::CreateConditionVariable());
198 CriticalSectionScoped cs(crit_sect.get());
199 int64_t start_ms = TickTime::MillisecondTimestamp();
200 EXPECT_FALSE(cond_var->SleepCS(*(crit_sect), kVeryShortWaitMs));
201 int64_t end_ms = TickTime::MillisecondTimestamp();
202 EXPECT_LE(start_ms + kVeryShortWaitMs, end_ms)
203 << "actual elapsed:" << end_ms - start_ms;
204}
205
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000206} // anonymous namespace
207
208} // namespace webrtc
tommicd255cc2016-01-19 13:13:14 -0800209
210#endif // defined(WEBRTC_WIN)