blob: 1e4f66530f64edeb037c275c0823b8d65da84196 [file] [log] [blame]
hta@webrtc.org3168e532012-06-20 06:45:56 +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
phoglund@webrtc.org99f7c912012-11-30 10:44:49 +000011#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
12
hta@webrtc.org3168e532012-06-20 06:45:56 +000013#include "gtest/gtest.h"
phoglund@webrtc.org99f7c912012-11-30 10:44:49 +000014#include "webrtc/system_wrappers/interface/sleep.h"
15#include "webrtc/system_wrappers/interface/thread_wrapper.h"
16#include "webrtc/system_wrappers/interface/trace.h"
17#include "webrtc/system_wrappers/source/unittest_utilities.h"
hta@webrtc.org3168e532012-06-20 06:45:56 +000018
19namespace webrtc {
20
21namespace {
22
23const bool kLogTrace = false; // Set to true to enable debug logging to stdout.
24
hta@webrtc.org3168e532012-06-20 06:45:56 +000025// Cause a process switch. Needed to avoid depending on
26// busy-wait in tests.
27static void SwitchProcess() {
28 // Note - sched_yield has been tried as process switch. This does
29 // not cause a process switch enough of the time for reliability.
30 SleepMs(1);
31}
32
33class ProtectedCount {
phoglund@webrtc.org99f7c912012-11-30 10:44:49 +000034public:
hta@webrtc.org3168e532012-06-20 06:45:56 +000035 explicit ProtectedCount(CriticalSectionWrapper* crit_sect)
36 : crit_sect_(crit_sect),
37 count_(0) {
38 }
39
40 void Increment() {
41 CriticalSectionScoped cs(crit_sect_);
42 ++count_;
hta@webrtc.org3168e532012-06-20 06:45:56 +000043 }
44
45 int Count() const {
46 CriticalSectionScoped cs(crit_sect_);
47 return count_;
48 }
49
phoglund@webrtc.org99f7c912012-11-30 10:44:49 +000050private:
hta@webrtc.org3168e532012-06-20 06:45:56 +000051 CriticalSectionWrapper* crit_sect_;
52 int count_;
53};
54
55class CritSectTest : public ::testing::Test {
phoglund@webrtc.org99f7c912012-11-30 10:44:49 +000056public:
hta@webrtc.org3168e532012-06-20 06:45:56 +000057 CritSectTest() : trace_(kLogTrace) {
58 }
59
60 // Waits a number of cycles for the count to reach a given value.
61 // Returns true if the target is reached or passed.
62 bool WaitForCount(int target, ProtectedCount* count) {
63 int loop_counter = 0;
64 // On Posix, this SwitchProcess() needs to be in a loop to make the
65 // test both fast and non-flaky.
66 // With 1 us wait as the switch, up to 7 rounds have been observed.
phoglund@webrtc.org99f7c912012-11-30 10:44:49 +000067 while (count->Count() < target && loop_counter < 100 * target) {
hta@webrtc.org3168e532012-06-20 06:45:56 +000068 ++loop_counter;
69 SwitchProcess();
70 }
hta@webrtc.org3168e532012-06-20 06:45:56 +000071 return (count->Count() >= target);
72 }
73
phoglund@webrtc.org99f7c912012-11-30 10:44:49 +000074private:
hta@webrtc.org3168e532012-06-20 06:45:56 +000075 ScopedTracing trace_;
76};
77
78bool LockUnlockThenStopRunFunction(void* obj) {
phoglund@webrtc.org99f7c912012-11-30 10:44:49 +000079 ProtectedCount* the_count = static_cast<ProtectedCount*>(obj);
hta@webrtc.org3168e532012-06-20 06:45:56 +000080 the_count->Increment();
hta@webrtc.org3168e532012-06-20 06:45:56 +000081 return false;
82}
83
84TEST_F(CritSectTest, ThreadWakesOnce) {
phoglund@webrtc.org99f7c912012-11-30 10:44:49 +000085 CriticalSectionWrapper* crit_sect =
86 CriticalSectionWrapper::CreateCriticalSection();
hta@webrtc.org3168e532012-06-20 06:45:56 +000087 ProtectedCount count(crit_sect);
88 ThreadWrapper* thread = ThreadWrapper::CreateThread(
89 &LockUnlockThenStopRunFunction, &count);
90 unsigned int id = 42;
91 crit_sect->Enter();
92 ASSERT_TRUE(thread->Start(id));
93 SwitchProcess();
94 // The critical section is of reentrant mode, so this should not release
95 // the lock, even though count.Count() locks and unlocks the critical section
96 // again.
97 // Thus, the thread should not be able to increment the count
98 ASSERT_EQ(0, count.Count());
99 crit_sect->Leave(); // This frees the thread to act.
100 EXPECT_TRUE(WaitForCount(1, &count));
101 EXPECT_TRUE(thread->Stop());
102 delete thread;
103 delete crit_sect;
104}
105
106bool LockUnlockRunFunction(void* obj) {
phoglund@webrtc.org99f7c912012-11-30 10:44:49 +0000107 ProtectedCount* the_count = static_cast<ProtectedCount*>(obj);
hta@webrtc.org3168e532012-06-20 06:45:56 +0000108 the_count->Increment();
109 SwitchProcess();
hta@webrtc.org3168e532012-06-20 06:45:56 +0000110 return true;
111}
112
113TEST_F(CritSectTest, ThreadWakesTwice) {
phoglund@webrtc.org99f7c912012-11-30 10:44:49 +0000114 CriticalSectionWrapper* crit_sect =
115 CriticalSectionWrapper::CreateCriticalSection();
hta@webrtc.org3168e532012-06-20 06:45:56 +0000116 ProtectedCount count(crit_sect);
117 ThreadWrapper* thread = ThreadWrapper::CreateThread(&LockUnlockRunFunction,
118 &count);
119 unsigned int id = 42;
120 crit_sect->Enter(); // Make sure counter stays 0 until we wait for it.
121 ASSERT_TRUE(thread->Start(id));
122 crit_sect->Leave();
123
124 // The thread is capable of grabbing the lock multiple times,
125 // incrementing counter once each time.
126 // It's possible for the count to be incremented by more than 2.
127 EXPECT_TRUE(WaitForCount(2, &count));
128 EXPECT_LE(2, count.Count());
129
130 // The thread does not increment while lock is held.
131 crit_sect->Enter();
132 int count_before = count.Count();
133 for (int i = 0; i < 10; i++) {
134 SwitchProcess();
135 }
136 EXPECT_EQ(count_before, count.Count());
137 crit_sect->Leave();
138
139 thread->SetNotAlive(); // Tell thread to exit once run function finishes.
140 SwitchProcess();
hta@webrtc.orga701c0e2013-04-09 12:36:28 +0000141 EXPECT_TRUE(WaitForCount(count_before + 1, &count));
hta@webrtc.org3168e532012-06-20 06:45:56 +0000142 EXPECT_TRUE(thread->Stop());
143 delete thread;
144 delete crit_sect;
145}
146
147} // anonymous namespace
148
149} // namespace webrtc