| /* | 
 |  *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | 
 |  * | 
 |  *  Use of this source code is governed by a BSD-style license | 
 |  *  that can be found in the LICENSE file in the root of the source | 
 |  *  tree. An additional intellectual property rights grant can be found | 
 |  *  in the file PATENTS.  All contributing project authors may | 
 |  *  be found in the AUTHORS file in the root of the source tree. | 
 |  */ | 
 |  | 
 | #include "webrtc/system_wrappers/interface/condition_variable_wrapper.h" | 
 |  | 
 | #include "testing/gtest/include/gtest/gtest.h" | 
 | #include "webrtc/system_wrappers/interface/critical_section_wrapper.h" | 
 | #include "webrtc/system_wrappers/interface/thread_wrapper.h" | 
 | #include "webrtc/system_wrappers/interface/trace.h" | 
 |  | 
 | namespace webrtc { | 
 |  | 
 | namespace { | 
 |  | 
 | const int kLongWaitMs = 100 * 1000; // A long time in testing terms | 
 | const int kShortWaitMs = 2 * 1000; // Long enough for process switches to happen | 
 |  | 
 | // A Baton is one possible control structure one can build using | 
 | // conditional variables. | 
 | // A Baton is always held by one and only one active thread - unlike | 
 | // a lock, it can never be free. | 
 | // One can pass it or grab it - both calls have timeouts. | 
 | // Note - a production tool would guard against passing it without | 
 | // grabbing it first. This one is for testing, so it doesn't. | 
 | class Baton { | 
 |  public: | 
 |   Baton() | 
 |     : giver_sect_(CriticalSectionWrapper::CreateCriticalSection()), | 
 |       crit_sect_(CriticalSectionWrapper::CreateCriticalSection()), | 
 |       cond_var_(ConditionVariableWrapper::CreateConditionVariable()), | 
 |       being_passed_(false), | 
 |       pass_count_(0) { | 
 |   } | 
 |  | 
 |   ~Baton() { | 
 |     delete giver_sect_; | 
 |     delete crit_sect_; | 
 |     delete cond_var_; | 
 |   } | 
 |  | 
 |   // Pass the baton. Returns false if baton is not picked up in |max_msecs|. | 
 |   // Only one process can pass at the same time; this property is | 
 |   // ensured by the |giver_sect_| lock. | 
 |   bool Pass(uint32_t max_msecs) { | 
 |     CriticalSectionScoped cs_giver(giver_sect_); | 
 |     CriticalSectionScoped cs(crit_sect_); | 
 |     SignalBatonAvailable(); | 
 |     const bool result = TakeBatonIfStillFree(max_msecs); | 
 |     if (result) { | 
 |       ++pass_count_; | 
 |     } | 
 |     return result; | 
 |   } | 
 |  | 
 |   // Grab the baton. Returns false if baton is not passed. | 
 |   bool Grab(uint32_t max_msecs) { | 
 |     CriticalSectionScoped cs(crit_sect_); | 
 |     return WaitUntilBatonOffered(max_msecs); | 
 |   } | 
 |  | 
 |   int PassCount() { | 
 |     // We don't allow polling PassCount() during a Pass()-call since there is | 
 |     // no guarantee that |pass_count_| is incremented until the Pass()-call | 
 |     // finishes. I.e. the Grab()-call may finish before |pass_count_| has been | 
 |     // incremented. | 
 |     // Thus, this function waits on giver_sect_. | 
 |     CriticalSectionScoped cs(giver_sect_); | 
 |     return pass_count_; | 
 |   } | 
 |  | 
 |  private: | 
 |   // Wait/Signal forms a classical semaphore on |being_passed_|. | 
 |   // These functions must be called with crit_sect_ held. | 
 |   bool WaitUntilBatonOffered(int timeout_ms) { | 
 |     while (!being_passed_) { | 
 |       if (!cond_var_->SleepCS(*crit_sect_, timeout_ms)) { | 
 |         return false; | 
 |       } | 
 |     } | 
 |     being_passed_ = false; | 
 |     cond_var_->Wake(); | 
 |     return true; | 
 |   } | 
 |  | 
 |   void SignalBatonAvailable() { | 
 |     assert(!being_passed_); | 
 |     being_passed_ = true; | 
 |     cond_var_->Wake(); | 
 |   } | 
 |  | 
 |   // Timeout extension: Wait for a limited time for someone else to | 
 |   // take it, and take it if it's not taken. | 
 |   // Returns true if resource is taken by someone else, false | 
 |   // if it is taken back by the caller. | 
 |   // This function must be called with both |giver_sect_| and | 
 |   // |crit_sect_| held. | 
 |   bool TakeBatonIfStillFree(int timeout_ms) { | 
 |     bool not_timeout = true; | 
 |     while (being_passed_ && not_timeout) { | 
 |       not_timeout = cond_var_->SleepCS(*crit_sect_, timeout_ms); | 
 |       // If we're woken up while variable is still held, we may have | 
 |       // gotten a wakeup destined for a grabber thread. | 
 |       // This situation is not treated specially here. | 
 |     } | 
 |     if (!being_passed_) { | 
 |       return true; | 
 |     } else { | 
 |       assert(!not_timeout); | 
 |       being_passed_ = false; | 
 |       return false; | 
 |     } | 
 |   } | 
 |  | 
 |   // Lock that ensures that there is only one thread in the active | 
 |   // part of Pass() at a time. | 
 |   // |giver_sect_| must always be acquired before |cond_var_|. | 
 |   CriticalSectionWrapper* giver_sect_; | 
 |   // Lock that protects |being_passed_|. | 
 |   CriticalSectionWrapper* crit_sect_; | 
 |   ConditionVariableWrapper* cond_var_; | 
 |   bool being_passed_; | 
 |   // Statistics information: Number of successfull passes. | 
 |   int pass_count_; | 
 | }; | 
 |  | 
 | // Function that waits on a Baton, and passes it right back. | 
 | // We expect these calls never to time out. | 
 | bool WaitingRunFunction(void* obj) { | 
 |   Baton* the_baton = static_cast<Baton*> (obj); | 
 |   EXPECT_TRUE(the_baton->Grab(kLongWaitMs)); | 
 |   EXPECT_TRUE(the_baton->Pass(kLongWaitMs)); | 
 |   return true; | 
 | } | 
 |  | 
 | class CondVarTest : public ::testing::Test { | 
 |  public: | 
 |   CondVarTest() {} | 
 |  | 
 |   virtual void SetUp() { | 
 |     thread_ = ThreadWrapper::CreateThread(&WaitingRunFunction, | 
 |                                           &baton_, "CondVarTest"); | 
 |     ASSERT_TRUE(thread_->Start()); | 
 |   } | 
 |  | 
 |   virtual void TearDown() { | 
 |     // We have to wake the thread in order to make it obey the stop order. | 
 |     // But we don't know if the thread has completed the run function, so | 
 |     // we don't know if it will exit before or after the Pass. | 
 |     // Thus, we need to pin it down inside its Run function (between Grab | 
 |     // and Pass). | 
 |     ASSERT_TRUE(baton_.Pass(kShortWaitMs)); | 
 |     ASSERT_TRUE(baton_.Grab(kShortWaitMs)); | 
 |     ASSERT_TRUE(thread_->Stop()); | 
 |   } | 
 |  | 
 |  protected: | 
 |   Baton baton_; | 
 |  | 
 |  private: | 
 |   rtc::scoped_ptr<ThreadWrapper> thread_; | 
 | }; | 
 |  | 
 | // The SetUp and TearDown functions use condition variables. | 
 | // This test verifies those pieces in isolation. | 
 | // Disabled due to flakiness.  See bug 4262 for details. | 
 | TEST_F(CondVarTest, DISABLED_InitFunctionsWork) { | 
 |   // All relevant asserts are in the SetUp and TearDown functions. | 
 | } | 
 |  | 
 | // This test verifies that one can use the baton multiple times. | 
 | TEST_F(CondVarTest, DISABLED_PassBatonMultipleTimes) { | 
 |   const int kNumberOfRounds = 2; | 
 |   for (int i = 0; i < kNumberOfRounds; ++i) { | 
 |     ASSERT_TRUE(baton_.Pass(kShortWaitMs)); | 
 |     ASSERT_TRUE(baton_.Grab(kShortWaitMs)); | 
 |   } | 
 |   EXPECT_EQ(2 * kNumberOfRounds, baton_.PassCount()); | 
 | } | 
 |  | 
 | }  // anonymous namespace | 
 |  | 
 | }  // namespace webrtc |