blob: c34c4ea0d8b437852e6105c11dc5cb5ef40b2691 [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
pbos@webrtc.orgacaf3a12013-05-27 15:07:45 +000011#include "webrtc/system_wrappers/interface/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"
14#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
15#include "webrtc/system_wrappers/interface/thread_wrapper.h"
16#include "webrtc/system_wrappers/interface/trace.h"
hta@webrtc.org72e3a892012-06-19 13:49:48 +000017
18namespace webrtc {
19
20namespace {
21
phoglund@webrtc.orga36d75a2012-11-14 09:55:04 +000022const int kLongWaitMs = 100 * 1000; // A long time in testing terms
23const int kShortWaitMs = 2 * 1000; // Long enough for process switches to happen
hta@webrtc.org72e3a892012-06-19 13:49:48 +000024
hta@webrtc.org72e3a892012-06-19 13:49:48 +000025// A Baton is one possible control structure one can build using
26// conditional variables.
27// A Baton is always held by one and only one active thread - unlike
28// a lock, it can never be free.
29// One can pass it or grab it - both calls have timeouts.
30// Note - a production tool would guard against passing it without
31// grabbing it first. This one is for testing, so it doesn't.
32class Baton {
33 public:
34 Baton()
35 : giver_sect_(CriticalSectionWrapper::CreateCriticalSection()),
36 crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
37 cond_var_(ConditionVariableWrapper::CreateConditionVariable()),
38 being_passed_(false),
39 pass_count_(0) {
40 }
41
42 ~Baton() {
43 delete giver_sect_;
44 delete crit_sect_;
45 delete cond_var_;
46 }
47
48 // Pass the baton. Returns false if baton is not picked up in |max_msecs|.
49 // Only one process can pass at the same time; this property is
50 // ensured by the |giver_sect_| lock.
pbos@webrtc.org046deb92013-04-09 09:06:11 +000051 bool Pass(uint32_t max_msecs) {
hta@webrtc.org72e3a892012-06-19 13:49:48 +000052 CriticalSectionScoped cs_giver(giver_sect_);
hta@webrtc.org72e3a892012-06-19 13:49:48 +000053 CriticalSectionScoped cs(crit_sect_);
54 SignalBatonAvailable();
55 const bool result = TakeBatonIfStillFree(max_msecs);
56 if (result) {
57 ++pass_count_;
hta@webrtc.org72e3a892012-06-19 13:49:48 +000058 }
59 return result;
60 }
61
62 // Grab the baton. Returns false if baton is not passed.
pbos@webrtc.org046deb92013-04-09 09:06:11 +000063 bool Grab(uint32_t max_msecs) {
hta@webrtc.org72e3a892012-06-19 13:49:48 +000064 CriticalSectionScoped cs(crit_sect_);
65 return WaitUntilBatonOffered(max_msecs);
66 }
67
68 int PassCount() {
69 // We don't allow polling PassCount() during a Pass()-call since there is
70 // no guarantee that |pass_count_| is incremented until the Pass()-call
71 // finishes. I.e. the Grab()-call may finish before |pass_count_| has been
72 // incremented.
73 // Thus, this function waits on giver_sect_.
74 CriticalSectionScoped cs(giver_sect_);
75 return pass_count_;
76 }
77
78 private:
79 // Wait/Signal forms a classical semaphore on |being_passed_|.
80 // These functions must be called with crit_sect_ held.
81 bool WaitUntilBatonOffered(int timeout_ms) {
82 while (!being_passed_) {
hta@webrtc.org72e3a892012-06-19 13:49:48 +000083 if (!cond_var_->SleepCS(*crit_sect_, timeout_ms)) {
hta@webrtc.org72e3a892012-06-19 13:49:48 +000084 return false;
85 }
86 }
87 being_passed_ = false;
88 cond_var_->Wake();
89 return true;
90 }
91
92 void SignalBatonAvailable() {
93 assert(!being_passed_);
94 being_passed_ = true;
hta@webrtc.org72e3a892012-06-19 13:49:48 +000095 cond_var_->Wake();
96 }
97
98 // Timeout extension: Wait for a limited time for someone else to
99 // take it, and take it if it's not taken.
100 // Returns true if resource is taken by someone else, false
101 // if it is taken back by the caller.
102 // This function must be called with both |giver_sect_| and
103 // |crit_sect_| held.
104 bool TakeBatonIfStillFree(int timeout_ms) {
105 bool not_timeout = true;
106 while (being_passed_ && not_timeout) {
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000107 not_timeout = cond_var_->SleepCS(*crit_sect_, timeout_ms);
108 // If we're woken up while variable is still held, we may have
109 // gotten a wakeup destined for a grabber thread.
110 // This situation is not treated specially here.
111 }
112 if (!being_passed_) {
113 return true;
114 } else {
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000115 assert(!not_timeout);
116 being_passed_ = false;
117 return false;
118 }
119 }
120
121 // Lock that ensures that there is only one thread in the active
122 // part of Pass() at a time.
123 // |giver_sect_| must always be acquired before |cond_var_|.
124 CriticalSectionWrapper* giver_sect_;
125 // Lock that protects |being_passed_|.
126 CriticalSectionWrapper* crit_sect_;
127 ConditionVariableWrapper* cond_var_;
128 bool being_passed_;
129 // Statistics information: Number of successfull passes.
130 int pass_count_;
131};
132
133// Function that waits on a Baton, and passes it right back.
134// We expect these calls never to time out.
135bool WaitingRunFunction(void* obj) {
andrew@webrtc.org50419b02012-11-14 19:07:54 +0000136 Baton* the_baton = static_cast<Baton*> (obj);
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000137 EXPECT_TRUE(the_baton->Grab(kLongWaitMs));
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000138 EXPECT_TRUE(the_baton->Pass(kLongWaitMs));
139 return true;
140}
141
142class CondVarTest : public ::testing::Test {
143 public:
andresp@webrtc.org3c637cd2014-07-07 20:37:39 +0000144 CondVarTest() {}
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000145
146 virtual void SetUp() {
147 thread_ = ThreadWrapper::CreateThread(&WaitingRunFunction,
tommi@webrtc.org38492c52015-03-22 14:41:46 +0000148 &baton_, "CondVarTest");
pbos@webrtc.org86639732015-03-13 00:06:21 +0000149 ASSERT_TRUE(thread_->Start());
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000150 }
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));
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000159 ASSERT_TRUE(baton_.Grab(kShortWaitMs));
160 ASSERT_TRUE(thread_->Stop());
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000161 }
162
163 protected:
164 Baton baton_;
165
166 private:
tommi@webrtc.org361981f2015-03-19 14:44:18 +0000167 rtc::scoped_ptr<ThreadWrapper> thread_;
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000168};
169
170// The SetUp and TearDown functions use condition variables.
171// This test verifies those pieces in isolation.
tommi@webrtc.org5d32f432015-02-05 06:25:35 +0000172// Disabled due to flakiness. See bug 4262 for details.
173TEST_F(CondVarTest, DISABLED_InitFunctionsWork) {
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000174 // All relevant asserts are in the SetUp and TearDown functions.
175}
176
177// This test verifies that one can use the baton multiple times.
bjornv@webrtc.orgdc096f22015-02-04 09:14:14 +0000178TEST_F(CondVarTest, DISABLED_PassBatonMultipleTimes) {
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000179 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 }
phoglund@webrtc.orga36d75a2012-11-14 09:55:04 +0000184 EXPECT_EQ(2 * kNumberOfRounds, baton_.PassCount());
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000185}
186
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000187} // anonymous namespace
188
189} // namespace webrtc