| OLD | NEW |
| (Empty) |
| 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 // TODO(tommi): Remove completely. As is there is still some code for Windows | |
| 12 // that relies on ConditionVariableEventWin, but code has been removed on other | |
| 13 // platforms. | |
| 14 #if defined(WEBRTC_WIN) | |
| 15 | |
| 16 #include "webrtc/base/platform_thread.h" | |
| 17 #include "webrtc/base/timeutils.h" | |
| 18 #include "webrtc/system_wrappers/include/critical_section_wrapper.h" | |
| 19 #include "webrtc/system_wrappers/source/condition_variable_event_win.h" | |
| 20 #include "webrtc/test/gtest.h" | |
| 21 | |
| 22 namespace webrtc { | |
| 23 | |
| 24 namespace { | |
| 25 | |
| 26 const int kLongWaitMs = 100 * 1000; // A long time in testing terms | |
| 27 const int kShortWaitMs = 2 * 1000; // Long enough for process switches to happen | |
| 28 const int kVeryShortWaitMs = 20; // Used when we want a timeout | |
| 29 | |
| 30 // A Baton is one possible control structure one can build using | |
| 31 // conditional variables. | |
| 32 // A Baton is always held by one and only one active thread - unlike | |
| 33 // a lock, it can never be free. | |
| 34 // One can pass it or grab it - both calls have timeouts. | |
| 35 // Note - a production tool would guard against passing it without | |
| 36 // grabbing it first. This one is for testing, so it doesn't. | |
| 37 class Baton { | |
| 38 public: | |
| 39 Baton() | |
| 40 : being_passed_(false), | |
| 41 pass_count_(0) { | |
| 42 InitializeCriticalSection(&crit_sect_); | |
| 43 } | |
| 44 | |
| 45 ~Baton() { | |
| 46 DeleteCriticalSection(&crit_sect_); | |
| 47 } | |
| 48 | |
| 49 // Pass the baton. Returns false if baton is not picked up in |max_msecs|. | |
| 50 // Only one process can pass at the same time; this property is | |
| 51 // ensured by the |giver_sect_| lock. | |
| 52 bool Pass(uint32_t max_msecs) { | |
| 53 CriticalSectionScoped cs_giver(&giver_sect_); | |
| 54 EnterCriticalSection(&crit_sect_); | |
| 55 SignalBatonAvailable(); | |
| 56 const bool result = TakeBatonIfStillFree(max_msecs); | |
| 57 if (result) { | |
| 58 ++pass_count_; | |
| 59 } | |
| 60 LeaveCriticalSection(&crit_sect_); | |
| 61 return result; | |
| 62 } | |
| 63 | |
| 64 // Grab the baton. Returns false if baton is not passed. | |
| 65 bool Grab(uint32_t max_msecs) { | |
| 66 EnterCriticalSection(&crit_sect_); | |
| 67 bool ret = WaitUntilBatonOffered(max_msecs); | |
| 68 LeaveCriticalSection(&crit_sect_); | |
| 69 return ret; | |
| 70 } | |
| 71 | |
| 72 int PassCount() { | |
| 73 // We don't allow polling PassCount() during a Pass()-call since there is | |
| 74 // no guarantee that |pass_count_| is incremented until the Pass()-call | |
| 75 // finishes. I.e. the Grab()-call may finish before |pass_count_| has been | |
| 76 // incremented. | |
| 77 // Thus, this function waits on giver_sect_. | |
| 78 CriticalSectionScoped cs(&giver_sect_); | |
| 79 return pass_count_; | |
| 80 } | |
| 81 | |
| 82 private: | |
| 83 // Wait/Signal forms a classical semaphore on |being_passed_|. | |
| 84 // These functions must be called with crit_sect_ held. | |
| 85 bool WaitUntilBatonOffered(int timeout_ms) { | |
| 86 while (!being_passed_) { | |
| 87 if (!cond_var_.SleepCS(&crit_sect_, timeout_ms)) { | |
| 88 return false; | |
| 89 } | |
| 90 } | |
| 91 being_passed_ = false; | |
| 92 cond_var_.Wake(); | |
| 93 return true; | |
| 94 } | |
| 95 | |
| 96 void SignalBatonAvailable() { | |
| 97 assert(!being_passed_); | |
| 98 being_passed_ = true; | |
| 99 cond_var_.Wake(); | |
| 100 } | |
| 101 | |
| 102 // Timeout extension: Wait for a limited time for someone else to | |
| 103 // take it, and take it if it's not taken. | |
| 104 // Returns true if resource is taken by someone else, false | |
| 105 // if it is taken back by the caller. | |
| 106 // This function must be called with both |giver_sect_| and | |
| 107 // |crit_sect_| held. | |
| 108 bool TakeBatonIfStillFree(int timeout_ms) { | |
| 109 bool not_timeout = true; | |
| 110 while (being_passed_ && not_timeout) { | |
| 111 not_timeout = cond_var_.SleepCS(&crit_sect_, timeout_ms); | |
| 112 // If we're woken up while variable is still held, we may have | |
| 113 // gotten a wakeup destined for a grabber thread. | |
| 114 // This situation is not treated specially here. | |
| 115 } | |
| 116 if (!being_passed_) | |
| 117 return true; | |
| 118 assert(!not_timeout); | |
| 119 being_passed_ = false; | |
| 120 return false; | |
| 121 } | |
| 122 | |
| 123 // Lock that ensures that there is only one thread in the active | |
| 124 // part of Pass() at a time. | |
| 125 // |giver_sect_| must always be acquired before |cond_var_|. | |
| 126 CriticalSectionWrapper giver_sect_; | |
| 127 // Lock that protects |being_passed_|. | |
| 128 CRITICAL_SECTION crit_sect_; | |
| 129 ConditionVariableEventWin cond_var_; | |
| 130 bool being_passed_; | |
| 131 // Statistics information: Number of successfull passes. | |
| 132 int pass_count_; | |
| 133 }; | |
| 134 | |
| 135 // Function that waits on a Baton, and passes it right back. | |
| 136 // We expect these calls never to time out. | |
| 137 bool WaitingRunFunction(void* obj) { | |
| 138 Baton* the_baton = static_cast<Baton*> (obj); | |
| 139 EXPECT_TRUE(the_baton->Grab(kLongWaitMs)); | |
| 140 EXPECT_TRUE(the_baton->Pass(kLongWaitMs)); | |
| 141 return true; | |
| 142 } | |
| 143 | |
| 144 class CondVarTest : public ::testing::Test { | |
| 145 public: | |
| 146 CondVarTest() : thread_(&WaitingRunFunction, &baton_, "CondVarTest") {} | |
| 147 | |
| 148 virtual void SetUp() { | |
| 149 thread_.Start(); | |
| 150 } | |
| 151 | |
| 152 virtual void TearDown() { | |
| 153 // We have to wake the thread in order to make it obey the stop order. | |
| 154 // But we don't know if the thread has completed the run function, so | |
| 155 // we don't know if it will exit before or after the Pass. | |
| 156 // Thus, we need to pin it down inside its Run function (between Grab | |
| 157 // and Pass). | |
| 158 ASSERT_TRUE(baton_.Pass(kShortWaitMs)); | |
| 159 ASSERT_TRUE(baton_.Grab(kShortWaitMs)); | |
| 160 thread_.Stop(); | |
| 161 } | |
| 162 | |
| 163 protected: | |
| 164 Baton baton_; | |
| 165 | |
| 166 private: | |
| 167 rtc::PlatformThread thread_; | |
| 168 }; | |
| 169 | |
| 170 // The SetUp and TearDown functions use condition variables. | |
| 171 // This test verifies those pieces in isolation. | |
| 172 // Disabled due to flakiness. See bug 4262 for details. | |
| 173 TEST_F(CondVarTest, DISABLED_InitFunctionsWork) { | |
| 174 // All relevant asserts are in the SetUp and TearDown functions. | |
| 175 } | |
| 176 | |
| 177 // This test verifies that one can use the baton multiple times. | |
| 178 TEST_F(CondVarTest, DISABLED_PassBatonMultipleTimes) { | |
| 179 const int kNumberOfRounds = 2; | |
| 180 for (int i = 0; i < kNumberOfRounds; ++i) { | |
| 181 ASSERT_TRUE(baton_.Pass(kShortWaitMs)); | |
| 182 ASSERT_TRUE(baton_.Grab(kShortWaitMs)); | |
| 183 } | |
| 184 EXPECT_EQ(2 * kNumberOfRounds, baton_.PassCount()); | |
| 185 } | |
| 186 | |
| 187 TEST(CondVarWaitTest, WaitingWaits) { | |
| 188 CRITICAL_SECTION crit_sect; | |
| 189 InitializeCriticalSection(&crit_sect); | |
| 190 ConditionVariableEventWin cond_var; | |
| 191 EnterCriticalSection(&crit_sect); | |
| 192 int64_t start_ms = rtc::TimeMillis(); | |
| 193 EXPECT_FALSE(cond_var.SleepCS(&crit_sect, kVeryShortWaitMs)); | |
| 194 int64_t end_ms = rtc::TimeMillis(); | |
| 195 EXPECT_LE(start_ms + kVeryShortWaitMs, end_ms) | |
| 196 << "actual elapsed:" << end_ms - start_ms; | |
| 197 LeaveCriticalSection(&crit_sect); | |
| 198 DeleteCriticalSection(&crit_sect); | |
| 199 } | |
| 200 | |
| 201 } // anonymous namespace | |
| 202 | |
| 203 } // namespace webrtc | |
| 204 | |
| 205 #endif // defined(WEBRTC_WIN) | |
| OLD | NEW |