blob: ed845cc21e72be143e7dca0f2627f354e63ffbcb [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
pbos@webrtc.orgacaf3a12013-05-27 15:07:45 +000013#include "testing/gtest/include/gtest/gtest.h"
hta3866c4f2015-10-20 09:31:01 -070014#include "webrtc/base/scoped_ptr.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010015#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
16#include "webrtc/system_wrappers/include/thread_wrapper.h"
17#include "webrtc/system_wrappers/include/tick_util.h"
18#include "webrtc/system_wrappers/include/trace.h"
hta@webrtc.org72e3a892012-06-19 13:49:48 +000019
20namespace webrtc {
21
22namespace {
23
phoglund@webrtc.orga36d75a2012-11-14 09:55:04 +000024const int kLongWaitMs = 100 * 1000; // A long time in testing terms
25const int kShortWaitMs = 2 * 1000; // Long enough for process switches to happen
hta3866c4f2015-10-20 09:31:01 -070026const int kVeryShortWaitMs = 20; // Used when we want a timeout
hta@webrtc.org72e3a892012-06-19 13:49:48 +000027
hta@webrtc.org72e3a892012-06-19 13:49:48 +000028// A Baton is one possible control structure one can build using
29// conditional variables.
30// A Baton is always held by one and only one active thread - unlike
31// a lock, it can never be free.
32// One can pass it or grab it - both calls have timeouts.
33// Note - a production tool would guard against passing it without
34// grabbing it first. This one is for testing, so it doesn't.
35class Baton {
36 public:
37 Baton()
38 : giver_sect_(CriticalSectionWrapper::CreateCriticalSection()),
39 crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
40 cond_var_(ConditionVariableWrapper::CreateConditionVariable()),
41 being_passed_(false),
42 pass_count_(0) {
43 }
44
45 ~Baton() {
46 delete giver_sect_;
47 delete crit_sect_;
48 delete cond_var_;
49 }
50
51 // Pass the baton. Returns false if baton is not picked up in |max_msecs|.
52 // Only one process can pass at the same time; this property is
53 // ensured by the |giver_sect_| lock.
pbos@webrtc.org046deb92013-04-09 09:06:11 +000054 bool Pass(uint32_t max_msecs) {
hta@webrtc.org72e3a892012-06-19 13:49:48 +000055 CriticalSectionScoped cs_giver(giver_sect_);
hta@webrtc.org72e3a892012-06-19 13:49:48 +000056 CriticalSectionScoped cs(crit_sect_);
57 SignalBatonAvailable();
58 const bool result = TakeBatonIfStillFree(max_msecs);
59 if (result) {
60 ++pass_count_;
hta@webrtc.org72e3a892012-06-19 13:49:48 +000061 }
62 return result;
63 }
64
65 // Grab the baton. Returns false if baton is not passed.
pbos@webrtc.org046deb92013-04-09 09:06:11 +000066 bool Grab(uint32_t max_msecs) {
hta@webrtc.org72e3a892012-06-19 13:49:48 +000067 CriticalSectionScoped cs(crit_sect_);
68 return WaitUntilBatonOffered(max_msecs);
69 }
70
71 int PassCount() {
72 // We don't allow polling PassCount() during a Pass()-call since there is
73 // no guarantee that |pass_count_| is incremented until the Pass()-call
74 // finishes. I.e. the Grab()-call may finish before |pass_count_| has been
75 // incremented.
76 // Thus, this function waits on giver_sect_.
77 CriticalSectionScoped cs(giver_sect_);
78 return pass_count_;
79 }
80
81 private:
82 // Wait/Signal forms a classical semaphore on |being_passed_|.
83 // These functions must be called with crit_sect_ held.
84 bool WaitUntilBatonOffered(int timeout_ms) {
85 while (!being_passed_) {
hta@webrtc.org72e3a892012-06-19 13:49:48 +000086 if (!cond_var_->SleepCS(*crit_sect_, timeout_ms)) {
hta@webrtc.org72e3a892012-06-19 13:49:48 +000087 return false;
88 }
89 }
90 being_passed_ = false;
91 cond_var_->Wake();
92 return true;
93 }
94
95 void SignalBatonAvailable() {
96 assert(!being_passed_);
97 being_passed_ = true;
hta@webrtc.org72e3a892012-06-19 13:49:48 +000098 cond_var_->Wake();
99 }
100
101 // Timeout extension: Wait for a limited time for someone else to
102 // take it, and take it if it's not taken.
103 // Returns true if resource is taken by someone else, false
104 // if it is taken back by the caller.
105 // This function must be called with both |giver_sect_| and
106 // |crit_sect_| held.
107 bool TakeBatonIfStillFree(int timeout_ms) {
108 bool not_timeout = true;
109 while (being_passed_ && not_timeout) {
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000110 not_timeout = cond_var_->SleepCS(*crit_sect_, timeout_ms);
111 // If we're woken up while variable is still held, we may have
112 // gotten a wakeup destined for a grabber thread.
113 // This situation is not treated specially here.
114 }
115 if (!being_passed_) {
116 return true;
117 } else {
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000118 assert(!not_timeout);
119 being_passed_ = false;
120 return false;
121 }
122 }
123
124 // Lock that ensures that there is only one thread in the active
125 // part of Pass() at a time.
126 // |giver_sect_| must always be acquired before |cond_var_|.
127 CriticalSectionWrapper* giver_sect_;
128 // Lock that protects |being_passed_|.
129 CriticalSectionWrapper* crit_sect_;
130 ConditionVariableWrapper* cond_var_;
131 bool being_passed_;
132 // Statistics information: Number of successfull passes.
133 int pass_count_;
134};
135
136// Function that waits on a Baton, and passes it right back.
137// We expect these calls never to time out.
138bool WaitingRunFunction(void* obj) {
andrew@webrtc.org50419b02012-11-14 19:07:54 +0000139 Baton* the_baton = static_cast<Baton*> (obj);
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000140 EXPECT_TRUE(the_baton->Grab(kLongWaitMs));
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000141 EXPECT_TRUE(the_baton->Pass(kLongWaitMs));
142 return true;
143}
144
145class CondVarTest : public ::testing::Test {
146 public:
andresp@webrtc.org3c637cd2014-07-07 20:37:39 +0000147 CondVarTest() {}
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000148
149 virtual void SetUp() {
150 thread_ = ThreadWrapper::CreateThread(&WaitingRunFunction,
tommi@webrtc.org38492c52015-03-22 14:41:46 +0000151 &baton_, "CondVarTest");
pbos@webrtc.org86639732015-03-13 00:06:21 +0000152 ASSERT_TRUE(thread_->Start());
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000153 }
154
155 virtual void TearDown() {
156 // We have to wake the thread in order to make it obey the stop order.
157 // But we don't know if the thread has completed the run function, so
158 // we don't know if it will exit before or after the Pass.
159 // Thus, we need to pin it down inside its Run function (between Grab
160 // and Pass).
161 ASSERT_TRUE(baton_.Pass(kShortWaitMs));
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000162 ASSERT_TRUE(baton_.Grab(kShortWaitMs));
163 ASSERT_TRUE(thread_->Stop());
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000164 }
165
166 protected:
167 Baton baton_;
168
169 private:
tommi@webrtc.org361981f2015-03-19 14:44:18 +0000170 rtc::scoped_ptr<ThreadWrapper> thread_;
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000171};
172
173// The SetUp and TearDown functions use condition variables.
174// This test verifies those pieces in isolation.
tommi@webrtc.org5d32f432015-02-05 06:25:35 +0000175// Disabled due to flakiness. See bug 4262 for details.
176TEST_F(CondVarTest, DISABLED_InitFunctionsWork) {
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000177 // All relevant asserts are in the SetUp and TearDown functions.
178}
179
180// This test verifies that one can use the baton multiple times.
bjornv@webrtc.orgdc096f22015-02-04 09:14:14 +0000181TEST_F(CondVarTest, DISABLED_PassBatonMultipleTimes) {
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000182 const int kNumberOfRounds = 2;
183 for (int i = 0; i < kNumberOfRounds; ++i) {
184 ASSERT_TRUE(baton_.Pass(kShortWaitMs));
185 ASSERT_TRUE(baton_.Grab(kShortWaitMs));
186 }
phoglund@webrtc.orga36d75a2012-11-14 09:55:04 +0000187 EXPECT_EQ(2 * kNumberOfRounds, baton_.PassCount());
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000188}
189
hta3866c4f2015-10-20 09:31:01 -0700190TEST(CondVarWaitTest, WaitingWaits) {
191 rtc::scoped_ptr<CriticalSectionWrapper> crit_sect(
192 CriticalSectionWrapper::CreateCriticalSection());
193 rtc::scoped_ptr<ConditionVariableWrapper> cond_var(
194 ConditionVariableWrapper::CreateConditionVariable());
195 CriticalSectionScoped cs(crit_sect.get());
196 int64_t start_ms = TickTime::MillisecondTimestamp();
197 EXPECT_FALSE(cond_var->SleepCS(*(crit_sect), kVeryShortWaitMs));
198 int64_t end_ms = TickTime::MillisecondTimestamp();
199 EXPECT_LE(start_ms + kVeryShortWaitMs, end_ms)
200 << "actual elapsed:" << end_ms - start_ms;
201}
202
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000203} // anonymous namespace
204
205} // namespace webrtc