Home | History | Annotate | Download | only in source
      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