text: /*
   *  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 "system_wrappers/interface/condition_variable_wrapper.h"
  
  #include "gtest/gtest.h"
  #include "system_wrappers/interface/critical_section_wrapper.h"
  #include "system_wrappers/interface/thread_wrapper.h"
  #include "system_wrappers/interface/trace.h"
  #include "system_wrappers/source/unittest_utilities.h"
  
  namespace webrtc {
  
  namespace {
  
  const int kLogTrace = false;  // Set to true to enable debug logging to stdout.
  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(WebRtc_UWord32 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(WebRtc_UWord32 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()
      : trace_(kLogTrace) {
    }
  
    virtual void SetUp() {
      thread_ = ThreadWrapper::CreateThread(&WaitingRunFunction,
                                            &baton_);
      unsigned int id = 42;
      ASSERT_TRUE(thread_->Start(id));
    }
  
    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));
      thread_->SetNotAlive();
      ASSERT_TRUE(baton_.Grab(kShortWaitMs));
      ASSERT_TRUE(thread_->Stop());
      delete thread_;
    }
  
   protected:
    Baton baton_;
  
   private:
    ScopedTracing trace_;
    ThreadWrapper* thread_;
  };
  
  // The SetUp and TearDown functions use condition variables.
  // This test verifies those pieces in isolation.
  TEST_F(CondVarTest, 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, 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
  