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