blob: 5fc6bc6b73e34622468888077fe82d67f5fb8f9a [file] [log] [blame]
hta@webrtc.org72e3a892012-06-19 13:49:48 +00001/*
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
tommicd255cc2016-01-19 13:13:14 -080011// TODO(tommi): Remove completely. As is there is still some code for Windows
Tommie8493322016-01-20 13:36:31 +010012// that relies on ConditionVariableEventWin, but code has been removed on other
tommicd255cc2016-01-19 13:13:14 -080013// platforms.
14#if defined(WEBRTC_WIN)
15
Tommie8493322016-01-20 13:36:31 +010016#include "webrtc/system_wrappers/source/condition_variable_event_win.h"
17
pbos@webrtc.orgacaf3a12013-05-27 15:07:45 +000018#include "testing/gtest/include/gtest/gtest.h"
pbos12411ef2015-11-23 14:47:56 -080019#include "webrtc/base/platform_thread.h"
Niels Möllerd28db7f2016-05-10 16:31:47 +020020#include "webrtc/base/timeutils.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010021#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010022#include "webrtc/system_wrappers/include/trace.h"
hta@webrtc.org72e3a892012-06-19 13:49:48 +000023
24namespace webrtc {
25
26namespace {
27
phoglund@webrtc.orga36d75a2012-11-14 09:55:04 +000028const int kLongWaitMs = 100 * 1000; // A long time in testing terms
29const int kShortWaitMs = 2 * 1000; // Long enough for process switches to happen
hta3866c4f2015-10-20 09:31:01 -070030const int kVeryShortWaitMs = 20; // Used when we want a timeout
hta@webrtc.org72e3a892012-06-19 13:49:48 +000031
hta@webrtc.org72e3a892012-06-19 13:49:48 +000032// A Baton is one possible control structure one can build using
33// conditional variables.
34// A Baton is always held by one and only one active thread - unlike
35// a lock, it can never be free.
36// One can pass it or grab it - both calls have timeouts.
37// Note - a production tool would guard against passing it without
38// grabbing it first. This one is for testing, so it doesn't.
39class Baton {
40 public:
41 Baton()
Tommie8493322016-01-20 13:36:31 +010042 : being_passed_(false),
hta@webrtc.org72e3a892012-06-19 13:49:48 +000043 pass_count_(0) {
Tommie8493322016-01-20 13:36:31 +010044 InitializeCriticalSection(&crit_sect_);
hta@webrtc.org72e3a892012-06-19 13:49:48 +000045 }
46
47 ~Baton() {
Tommie8493322016-01-20 13:36:31 +010048 DeleteCriticalSection(&crit_sect_);
hta@webrtc.org72e3a892012-06-19 13:49:48 +000049 }
50
51 // Pass the baton. Returns false if baton is not picked up in |max_msecs|.
52 // Only one process can pass at the same time; this property is
53 // ensured by the |giver_sect_| lock.
pbos@webrtc.org046deb92013-04-09 09:06:11 +000054 bool Pass(uint32_t max_msecs) {
Tommie8493322016-01-20 13:36:31 +010055 CriticalSectionScoped cs_giver(&giver_sect_);
56 EnterCriticalSection(&crit_sect_);
hta@webrtc.org72e3a892012-06-19 13:49:48 +000057 SignalBatonAvailable();
58 const bool result = TakeBatonIfStillFree(max_msecs);
59 if (result) {
60 ++pass_count_;
hta@webrtc.org72e3a892012-06-19 13:49:48 +000061 }
Tommie8493322016-01-20 13:36:31 +010062 LeaveCriticalSection(&crit_sect_);
hta@webrtc.org72e3a892012-06-19 13:49:48 +000063 return result;
64 }
65
66 // Grab the baton. Returns false if baton is not passed.
pbos@webrtc.org046deb92013-04-09 09:06:11 +000067 bool Grab(uint32_t max_msecs) {
Tommie8493322016-01-20 13:36:31 +010068 EnterCriticalSection(&crit_sect_);
69 bool ret = WaitUntilBatonOffered(max_msecs);
70 LeaveCriticalSection(&crit_sect_);
71 return ret;
hta@webrtc.org72e3a892012-06-19 13:49:48 +000072 }
73
74 int PassCount() {
75 // We don't allow polling PassCount() during a Pass()-call since there is
76 // no guarantee that |pass_count_| is incremented until the Pass()-call
77 // finishes. I.e. the Grab()-call may finish before |pass_count_| has been
78 // incremented.
79 // Thus, this function waits on giver_sect_.
Tommie8493322016-01-20 13:36:31 +010080 CriticalSectionScoped cs(&giver_sect_);
hta@webrtc.org72e3a892012-06-19 13:49:48 +000081 return pass_count_;
82 }
83
84 private:
85 // Wait/Signal forms a classical semaphore on |being_passed_|.
86 // These functions must be called with crit_sect_ held.
87 bool WaitUntilBatonOffered(int timeout_ms) {
88 while (!being_passed_) {
Tommie8493322016-01-20 13:36:31 +010089 if (!cond_var_.SleepCS(&crit_sect_, timeout_ms)) {
hta@webrtc.org72e3a892012-06-19 13:49:48 +000090 return false;
91 }
92 }
93 being_passed_ = false;
Tommie8493322016-01-20 13:36:31 +010094 cond_var_.Wake();
hta@webrtc.org72e3a892012-06-19 13:49:48 +000095 return true;
96 }
97
98 void SignalBatonAvailable() {
99 assert(!being_passed_);
100 being_passed_ = true;
Tommie8493322016-01-20 13:36:31 +0100101 cond_var_.Wake();
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000102 }
103
104 // Timeout extension: Wait for a limited time for someone else to
105 // take it, and take it if it's not taken.
106 // Returns true if resource is taken by someone else, false
107 // if it is taken back by the caller.
108 // This function must be called with both |giver_sect_| and
109 // |crit_sect_| held.
110 bool TakeBatonIfStillFree(int timeout_ms) {
111 bool not_timeout = true;
112 while (being_passed_ && not_timeout) {
Tommie8493322016-01-20 13:36:31 +0100113 not_timeout = cond_var_.SleepCS(&crit_sect_, timeout_ms);
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000114 // If we're woken up while variable is still held, we may have
115 // gotten a wakeup destined for a grabber thread.
116 // This situation is not treated specially here.
117 }
Tommie8493322016-01-20 13:36:31 +0100118 if (!being_passed_)
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000119 return true;
Tommie8493322016-01-20 13:36:31 +0100120 assert(!not_timeout);
121 being_passed_ = false;
122 return false;
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000123 }
124
125 // Lock that ensures that there is only one thread in the active
126 // part of Pass() at a time.
127 // |giver_sect_| must always be acquired before |cond_var_|.
Tommie8493322016-01-20 13:36:31 +0100128 CriticalSectionWrapper giver_sect_;
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000129 // Lock that protects |being_passed_|.
Tommie8493322016-01-20 13:36:31 +0100130 CRITICAL_SECTION crit_sect_;
131 ConditionVariableEventWin cond_var_;
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000132 bool being_passed_;
133 // Statistics information: Number of successfull passes.
134 int pass_count_;
135};
136
137// Function that waits on a Baton, and passes it right back.
138// We expect these calls never to time out.
139bool WaitingRunFunction(void* obj) {
andrew@webrtc.org50419b02012-11-14 19:07:54 +0000140 Baton* the_baton = static_cast<Baton*> (obj);
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000141 EXPECT_TRUE(the_baton->Grab(kLongWaitMs));
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000142 EXPECT_TRUE(the_baton->Pass(kLongWaitMs));
143 return true;
144}
145
146class CondVarTest : public ::testing::Test {
147 public:
Peter Boström8c38e8b2015-11-26 17:45:47 +0100148 CondVarTest() : thread_(&WaitingRunFunction, &baton_, "CondVarTest") {}
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000149
150 virtual void SetUp() {
Peter Boström8c38e8b2015-11-26 17:45:47 +0100151 thread_.Start();
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000152 }
153
154 virtual void TearDown() {
155 // We have to wake the thread in order to make it obey the stop order.
156 // But we don't know if the thread has completed the run function, so
157 // we don't know if it will exit before or after the Pass.
158 // Thus, we need to pin it down inside its Run function (between Grab
159 // and Pass).
160 ASSERT_TRUE(baton_.Pass(kShortWaitMs));
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000161 ASSERT_TRUE(baton_.Grab(kShortWaitMs));
Peter Boström8c38e8b2015-11-26 17:45:47 +0100162 thread_.Stop();
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000163 }
164
165 protected:
166 Baton baton_;
167
168 private:
Peter Boström8c38e8b2015-11-26 17:45:47 +0100169 rtc::PlatformThread thread_;
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000170};
171
172// The SetUp and TearDown functions use condition variables.
173// This test verifies those pieces in isolation.
tommi@webrtc.org5d32f432015-02-05 06:25:35 +0000174// Disabled due to flakiness. See bug 4262 for details.
175TEST_F(CondVarTest, DISABLED_InitFunctionsWork) {
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000176 // All relevant asserts are in the SetUp and TearDown functions.
177}
178
179// This test verifies that one can use the baton multiple times.
bjornv@webrtc.orgdc096f22015-02-04 09:14:14 +0000180TEST_F(CondVarTest, DISABLED_PassBatonMultipleTimes) {
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000181 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 }
phoglund@webrtc.orga36d75a2012-11-14 09:55:04 +0000186 EXPECT_EQ(2 * kNumberOfRounds, baton_.PassCount());
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000187}
188
hta3866c4f2015-10-20 09:31:01 -0700189TEST(CondVarWaitTest, WaitingWaits) {
Tommie8493322016-01-20 13:36:31 +0100190 CRITICAL_SECTION crit_sect;
191 InitializeCriticalSection(&crit_sect);
192 ConditionVariableEventWin cond_var;
193 EnterCriticalSection(&crit_sect);
Niels Möllerd28db7f2016-05-10 16:31:47 +0200194 int64_t start_ms = rtc::TimeMillis();
Tommie8493322016-01-20 13:36:31 +0100195 EXPECT_FALSE(cond_var.SleepCS(&crit_sect, kVeryShortWaitMs));
Niels Möllerd28db7f2016-05-10 16:31:47 +0200196 int64_t end_ms = rtc::TimeMillis();
hta3866c4f2015-10-20 09:31:01 -0700197 EXPECT_LE(start_ms + kVeryShortWaitMs, end_ms)
198 << "actual elapsed:" << end_ms - start_ms;
Tommie8493322016-01-20 13:36:31 +0100199 LeaveCriticalSection(&crit_sect);
200 DeleteCriticalSection(&crit_sect);
hta3866c4f2015-10-20 09:31:01 -0700201}
202
hta@webrtc.org72e3a892012-06-19 13:49:48 +0000203} // anonymous namespace
204
205} // namespace webrtc
tommicd255cc2016-01-19 13:13:14 -0800206
207#endif // defined(WEBRTC_WIN)