• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "webrtc/system_wrappers/include/condition_variable_wrapper.h"
12 
13 #include "testing/gtest/include/gtest/gtest.h"
14 #include "webrtc/base/platform_thread.h"
15 #include "webrtc/base/scoped_ptr.h"
16 #include "webrtc/system_wrappers/include/critical_section_wrapper.h"
17 #include "webrtc/system_wrappers/include/tick_util.h"
18 #include "webrtc/system_wrappers/include/trace.h"
19 
20 namespace webrtc {
21 
22 namespace {
23 
24 const int kLongWaitMs = 100 * 1000; // A long time in testing terms
25 const int kShortWaitMs = 2 * 1000; // Long enough for process switches to happen
26 const int kVeryShortWaitMs = 20; // Used when we want a timeout
27 
28 // 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.
35 class Baton {
36  public:
Baton()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 
~Baton()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.
Pass(uint32_t max_msecs)54   bool Pass(uint32_t max_msecs) {
55     CriticalSectionScoped cs_giver(giver_sect_);
56     CriticalSectionScoped cs(crit_sect_);
57     SignalBatonAvailable();
58     const bool result = TakeBatonIfStillFree(max_msecs);
59     if (result) {
60       ++pass_count_;
61     }
62     return result;
63   }
64 
65   // Grab the baton. Returns false if baton is not passed.
Grab(uint32_t max_msecs)66   bool Grab(uint32_t max_msecs) {
67     CriticalSectionScoped cs(crit_sect_);
68     return WaitUntilBatonOffered(max_msecs);
69   }
70 
PassCount()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.
WaitUntilBatonOffered(int timeout_ms)84   bool WaitUntilBatonOffered(int timeout_ms) {
85     while (!being_passed_) {
86       if (!cond_var_->SleepCS(*crit_sect_, timeout_ms)) {
87         return false;
88       }
89     }
90     being_passed_ = false;
91     cond_var_->Wake();
92     return true;
93   }
94 
SignalBatonAvailable()95   void SignalBatonAvailable() {
96     assert(!being_passed_);
97     being_passed_ = true;
98     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.
TakeBatonIfStillFree(int timeout_ms)107   bool TakeBatonIfStillFree(int timeout_ms) {
108     bool not_timeout = true;
109     while (being_passed_ && not_timeout) {
110       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 {
118       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.
WaitingRunFunction(void * obj)138 bool WaitingRunFunction(void* obj) {
139   Baton* the_baton = static_cast<Baton*> (obj);
140   EXPECT_TRUE(the_baton->Grab(kLongWaitMs));
141   EXPECT_TRUE(the_baton->Pass(kLongWaitMs));
142   return true;
143 }
144 
145 class CondVarTest : public ::testing::Test {
146  public:
CondVarTest()147   CondVarTest() : thread_(&WaitingRunFunction, &baton_, "CondVarTest") {}
148 
SetUp()149   virtual void SetUp() {
150     thread_.Start();
151   }
152 
TearDown()153   virtual void TearDown() {
154     // We have to wake the thread in order to make it obey the stop order.
155     // But we don't know if the thread has completed the run function, so
156     // we don't know if it will exit before or after the Pass.
157     // Thus, we need to pin it down inside its Run function (between Grab
158     // and Pass).
159     ASSERT_TRUE(baton_.Pass(kShortWaitMs));
160     ASSERT_TRUE(baton_.Grab(kShortWaitMs));
161     thread_.Stop();
162   }
163 
164  protected:
165   Baton baton_;
166 
167  private:
168   rtc::PlatformThread thread_;
169 };
170 
171 // The SetUp and TearDown functions use condition variables.
172 // This test verifies those pieces in isolation.
173 // Disabled due to flakiness.  See bug 4262 for details.
TEST_F(CondVarTest,DISABLED_InitFunctionsWork)174 TEST_F(CondVarTest, DISABLED_InitFunctionsWork) {
175   // All relevant asserts are in the SetUp and TearDown functions.
176 }
177 
178 // This test verifies that one can use the baton multiple times.
TEST_F(CondVarTest,DISABLED_PassBatonMultipleTimes)179 TEST_F(CondVarTest, DISABLED_PassBatonMultipleTimes) {
180   const int kNumberOfRounds = 2;
181   for (int i = 0; i < kNumberOfRounds; ++i) {
182     ASSERT_TRUE(baton_.Pass(kShortWaitMs));
183     ASSERT_TRUE(baton_.Grab(kShortWaitMs));
184   }
185   EXPECT_EQ(2 * kNumberOfRounds, baton_.PassCount());
186 }
187 
TEST(CondVarWaitTest,WaitingWaits)188 TEST(CondVarWaitTest, WaitingWaits) {
189   rtc::scoped_ptr<CriticalSectionWrapper> crit_sect(
190       CriticalSectionWrapper::CreateCriticalSection());
191   rtc::scoped_ptr<ConditionVariableWrapper> cond_var(
192       ConditionVariableWrapper::CreateConditionVariable());
193   CriticalSectionScoped cs(crit_sect.get());
194   int64_t start_ms = TickTime::MillisecondTimestamp();
195   EXPECT_FALSE(cond_var->SleepCS(*(crit_sect), kVeryShortWaitMs));
196   int64_t end_ms = TickTime::MillisecondTimestamp();
197   EXPECT_LE(start_ms + kVeryShortWaitMs, end_ms)
198       << "actual elapsed:" << end_ms - start_ms;
199 }
200 
201 }  // anonymous namespace
202 
203 }  // namespace webrtc
204