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