blob: d876b131e46673b5b7d8ce125ae1d36be814dd99 [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
pbos@webrtc.orgacaf3a12013-05-27 15:07:45 +000013#include "testing/gtest/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"
hta@webrtc.org3168e532012-06-20 06:45:56 +000017
18namespace webrtc {
19
20namespace {
21
hta@webrtc.org3168e532012-06-20 06:45:56 +000022// Cause a process switch. Needed to avoid depending on
23// busy-wait in tests.
24static void SwitchProcess() {
25 // Note - sched_yield has been tried as process switch. This does
26 // not cause a process switch enough of the time for reliability.
27 SleepMs(1);
28}
29
30class ProtectedCount {
phoglund@webrtc.org99f7c912012-11-30 10:44:49 +000031public:
hta@webrtc.org3168e532012-06-20 06:45:56 +000032 explicit ProtectedCount(CriticalSectionWrapper* crit_sect)
33 : crit_sect_(crit_sect),
34 count_(0) {
35 }
36
37 void Increment() {
38 CriticalSectionScoped cs(crit_sect_);
39 ++count_;
hta@webrtc.org3168e532012-06-20 06:45:56 +000040 }
41
42 int Count() const {
43 CriticalSectionScoped cs(crit_sect_);
44 return count_;
45 }
46
phoglund@webrtc.org99f7c912012-11-30 10:44:49 +000047private:
hta@webrtc.org3168e532012-06-20 06:45:56 +000048 CriticalSectionWrapper* crit_sect_;
49 int count_;
50};
51
52class CritSectTest : public ::testing::Test {
phoglund@webrtc.org99f7c912012-11-30 10:44:49 +000053public:
andresp@webrtc.org3c637cd2014-07-07 20:37:39 +000054 CritSectTest() {}
hta@webrtc.org3168e532012-06-20 06:45:56 +000055
56 // Waits a number of cycles for the count to reach a given value.
57 // Returns true if the target is reached or passed.
58 bool WaitForCount(int target, ProtectedCount* count) {
59 int loop_counter = 0;
60 // On Posix, this SwitchProcess() needs to be in a loop to make the
61 // test both fast and non-flaky.
62 // With 1 us wait as the switch, up to 7 rounds have been observed.
phoglund@webrtc.org99f7c912012-11-30 10:44:49 +000063 while (count->Count() < target && loop_counter < 100 * target) {
hta@webrtc.org3168e532012-06-20 06:45:56 +000064 ++loop_counter;
65 SwitchProcess();
66 }
hta@webrtc.org3168e532012-06-20 06:45:56 +000067 return (count->Count() >= target);
68 }
hta@webrtc.org3168e532012-06-20 06:45:56 +000069};
70
71bool LockUnlockThenStopRunFunction(void* obj) {
phoglund@webrtc.org99f7c912012-11-30 10:44:49 +000072 ProtectedCount* the_count = static_cast<ProtectedCount*>(obj);
hta@webrtc.org3168e532012-06-20 06:45:56 +000073 the_count->Increment();
hta@webrtc.org3168e532012-06-20 06:45:56 +000074 return false;
75}
76
andresp@webrtc.org7fb75ec2013-12-20 20:20:50 +000077TEST_F(CritSectTest, ThreadWakesOnce) NO_THREAD_SAFETY_ANALYSIS {
phoglund@webrtc.org99f7c912012-11-30 10:44:49 +000078 CriticalSectionWrapper* crit_sect =
79 CriticalSectionWrapper::CreateCriticalSection();
hta@webrtc.org3168e532012-06-20 06:45:56 +000080 ProtectedCount count(crit_sect);
81 ThreadWrapper* thread = ThreadWrapper::CreateThread(
82 &LockUnlockThenStopRunFunction, &count);
83 unsigned int id = 42;
84 crit_sect->Enter();
85 ASSERT_TRUE(thread->Start(id));
86 SwitchProcess();
87 // The critical section is of reentrant mode, so this should not release
88 // the lock, even though count.Count() locks and unlocks the critical section
89 // again.
90 // Thus, the thread should not be able to increment the count
91 ASSERT_EQ(0, count.Count());
92 crit_sect->Leave(); // This frees the thread to act.
93 EXPECT_TRUE(WaitForCount(1, &count));
94 EXPECT_TRUE(thread->Stop());
95 delete thread;
96 delete crit_sect;
97}
98
99bool LockUnlockRunFunction(void* obj) {
phoglund@webrtc.org99f7c912012-11-30 10:44:49 +0000100 ProtectedCount* the_count = static_cast<ProtectedCount*>(obj);
hta@webrtc.org3168e532012-06-20 06:45:56 +0000101 the_count->Increment();
102 SwitchProcess();
hta@webrtc.org3168e532012-06-20 06:45:56 +0000103 return true;
104}
105
andresp@webrtc.org7fb75ec2013-12-20 20:20:50 +0000106TEST_F(CritSectTest, ThreadWakesTwice) NO_THREAD_SAFETY_ANALYSIS {
phoglund@webrtc.org99f7c912012-11-30 10:44:49 +0000107 CriticalSectionWrapper* crit_sect =
108 CriticalSectionWrapper::CreateCriticalSection();
hta@webrtc.org3168e532012-06-20 06:45:56 +0000109 ProtectedCount count(crit_sect);
110 ThreadWrapper* thread = ThreadWrapper::CreateThread(&LockUnlockRunFunction,
111 &count);
112 unsigned int id = 42;
113 crit_sect->Enter(); // Make sure counter stays 0 until we wait for it.
114 ASSERT_TRUE(thread->Start(id));
115 crit_sect->Leave();
116
117 // The thread is capable of grabbing the lock multiple times,
118 // incrementing counter once each time.
119 // It's possible for the count to be incremented by more than 2.
120 EXPECT_TRUE(WaitForCount(2, &count));
121 EXPECT_LE(2, count.Count());
122
123 // The thread does not increment while lock is held.
124 crit_sect->Enter();
125 int count_before = count.Count();
126 for (int i = 0; i < 10; i++) {
127 SwitchProcess();
128 }
129 EXPECT_EQ(count_before, count.Count());
130 crit_sect->Leave();
131
hta@webrtc.org3168e532012-06-20 06:45:56 +0000132 SwitchProcess();
hta@webrtc.orga701c0e2013-04-09 12:36:28 +0000133 EXPECT_TRUE(WaitForCount(count_before + 1, &count));
hta@webrtc.org3168e532012-06-20 06:45:56 +0000134 EXPECT_TRUE(thread->Stop());
135 delete thread;
136 delete crit_sect;
137}
138
139} // anonymous namespace
140
141} // namespace webrtc