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 "system_wrappers/interface/condition_variable_wrapper.h" 12 13 #include "gtest/gtest.h" 14 #include "system_wrappers/interface/critical_section_wrapper.h" 15 #include "system_wrappers/interface/thread_wrapper.h" 16 #include "system_wrappers/interface/trace.h" 17 #include "system_wrappers/source/unittest_utilities.h" 18 19 namespace webrtc { 20 21 namespace { 22 23 const int kLogTrace = false; // Set to true to enable debug logging to stdout. 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 27 #define LOG(...) WEBRTC_TRACE(kTraceStateInfo, kTraceUtility, -1, __VA_ARGS__); 28 29 // A Baton is one possible control structure one can build using 30 // conditional variables. 31 // A Baton is always held by one and only one active thread - unlike 32 // a lock, it can never be free. 33 // One can pass it or grab it - both calls have timeouts. 34 // Note - a production tool would guard against passing it without 35 // grabbing it first. This one is for testing, so it doesn't. 36 class Baton { 37 public: 38 Baton() 39 : giver_sect_(CriticalSectionWrapper::CreateCriticalSection()), 40 crit_sect_(CriticalSectionWrapper::CreateCriticalSection()), 41 cond_var_(ConditionVariableWrapper::CreateConditionVariable()), 42 being_passed_(false), 43 pass_count_(0) { 44 } 45 46 ~Baton() { 47 delete giver_sect_; 48 delete crit_sect_; 49 delete cond_var_; 50 } 51 52 // Pass the baton. Returns false if baton is not picked up in |max_msecs|. 53 // Only one process can pass at the same time; this property is 54 // ensured by the |giver_sect_| lock. 55 bool Pass(WebRtc_UWord32 max_msecs) { 56 LOG("Locking giver_sect"); 57 CriticalSectionScoped cs_giver(giver_sect_); 58 LOG("Locked giver_sect, locking crit_sect"); 59 CriticalSectionScoped cs(crit_sect_); 60 SignalBatonAvailable(); 61 const bool result = TakeBatonIfStillFree(max_msecs); 62 if (result) { 63 ++pass_count_; 64 LOG("Pass count is %d", pass_count_); 65 } 66 return result; 67 } 68 69 // Grab the baton. Returns false if baton is not passed. 70 bool Grab(WebRtc_UWord32 max_msecs) { 71 CriticalSectionScoped cs(crit_sect_); 72 return WaitUntilBatonOffered(max_msecs); 73 } 74 75 int PassCount() { 76 // We don't allow polling PassCount() during a Pass()-call since there is 77 // no guarantee that |pass_count_| is incremented until the Pass()-call 78 // finishes. I.e. the Grab()-call may finish before |pass_count_| has been 79 // incremented. 80 // Thus, this function waits on giver_sect_. 81 CriticalSectionScoped cs(giver_sect_); 82 return pass_count_; 83 } 84 85 private: 86 // Wait/Signal forms a classical semaphore on |being_passed_|. 87 // These functions must be called with crit_sect_ held. 88 bool WaitUntilBatonOffered(int timeout_ms) { 89 while (!being_passed_) { 90 LOG("Wait waiting"); 91 if (!cond_var_->SleepCS(*crit_sect_, timeout_ms)) { 92 LOG("Wait timeout"); 93 return false; 94 } 95 } 96 being_passed_ = false; 97 cond_var_->Wake(); 98 return true; 99 } 100 101 void SignalBatonAvailable() { 102 assert(!being_passed_); 103 being_passed_ = true; 104 LOG("Signal waking"); 105 cond_var_->Wake(); 106 } 107 108 // Timeout extension: Wait for a limited time for someone else to 109 // take it, and take it if it's not taken. 110 // Returns true if resource is taken by someone else, false 111 // if it is taken back by the caller. 112 // This function must be called with both |giver_sect_| and 113 // |crit_sect_| held. 114 bool TakeBatonIfStillFree(int timeout_ms) { 115 bool not_timeout = true; 116 while (being_passed_ && not_timeout) { 117 LOG("Takeback waiting"); 118 not_timeout = cond_var_->SleepCS(*crit_sect_, timeout_ms); 119 // If we're woken up while variable is still held, we may have 120 // gotten a wakeup destined for a grabber thread. 121 // This situation is not treated specially here. 122 } 123 if (!being_passed_) { 124 return true; 125 } else { 126 LOG("Takeback grab"); 127 assert(!not_timeout); 128 being_passed_ = false; 129 return false; 130 } 131 } 132 133 // Lock that ensures that there is only one thread in the active 134 // part of Pass() at a time. 135 // |giver_sect_| must always be acquired before |cond_var_|. 136 CriticalSectionWrapper* giver_sect_; 137 // Lock that protects |being_passed_|. 138 CriticalSectionWrapper* crit_sect_; 139 ConditionVariableWrapper* cond_var_; 140 bool being_passed_; 141 // Statistics information: Number of successfull passes. 142 int pass_count_; 143 }; 144 145 // Function that waits on a Baton, and passes it right back. 146 // We expect these calls never to time out. 147 bool WaitingRunFunction(void* obj) { 148 Baton* the_baton = static_cast<Baton*> (obj); 149 LOG("Thread waiting"); 150 EXPECT_TRUE(the_baton->Grab(kLongWaitMs)); 151 LOG("Thread waking parent"); 152 EXPECT_TRUE(the_baton->Pass(kLongWaitMs)); 153 return true; 154 } 155 156 class CondVarTest : public ::testing::Test { 157 public: 158 CondVarTest() 159 : trace_(kLogTrace) { 160 } 161 162 virtual void SetUp() { 163 thread_ = ThreadWrapper::CreateThread(&WaitingRunFunction, 164 &baton_); 165 unsigned int id = 42; 166 ASSERT_TRUE(thread_->Start(id)); 167 } 168 169 virtual void TearDown() { 170 // We have to wake the thread in order to make it obey the stop order. 171 // But we don't know if the thread has completed the run function, so 172 // we don't know if it will exit before or after the Pass. 173 // Thus, we need to pin it down inside its Run function (between Grab 174 // and Pass). 175 ASSERT_TRUE(baton_.Pass(kShortWaitMs)); 176 thread_->SetNotAlive(); 177 ASSERT_TRUE(baton_.Grab(kShortWaitMs)); 178 ASSERT_TRUE(thread_->Stop()); 179 delete thread_; 180 } 181 182 protected: 183 Baton baton_; 184 185 private: 186 ScopedTracing trace_; 187 ThreadWrapper* thread_; 188 }; 189 190 // The SetUp and TearDown functions use condition variables. 191 // This test verifies those pieces in isolation. 192 TEST_F(CondVarTest, InitFunctionsWork) { 193 // All relevant asserts are in the SetUp and TearDown functions. 194 } 195 196 // This test verifies that one can use the baton multiple times. 197 TEST_F(CondVarTest, PassBatonMultipleTimes) { 198 const int kNumberOfRounds = 2; 199 for (int i = 0; i < kNumberOfRounds; ++i) { 200 ASSERT_TRUE(baton_.Pass(kShortWaitMs)); 201 ASSERT_TRUE(baton_.Grab(kShortWaitMs)); 202 } 203 EXPECT_EQ(2*kNumberOfRounds, baton_.PassCount()); 204 } 205 206 } // anonymous namespace 207 208 } // namespace webrtc 209