blob: 9b497b426a4553a6bebf7ece8c64d1f7794da1d6 [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);
tommi@webrtc.org361981f2015-03-19 14:44:18 +000081 rtc::scoped_ptr<ThreadWrapper> thread = ThreadWrapper::CreateThread(
hta@webrtc.org3168e532012-06-20 06:45:56 +000082 &LockUnlockThenStopRunFunction, &count);
hta@webrtc.org3168e532012-06-20 06:45:56 +000083 crit_sect->Enter();
pbos@webrtc.org86639732015-03-13 00:06:21 +000084 ASSERT_TRUE(thread->Start());
hta@webrtc.org3168e532012-06-20 06:45:56 +000085 SwitchProcess();
86 // The critical section is of reentrant mode, so this should not release
87 // the lock, even though count.Count() locks and unlocks the critical section
88 // again.
89 // Thus, the thread should not be able to increment the count
90 ASSERT_EQ(0, count.Count());
91 crit_sect->Leave(); // This frees the thread to act.
92 EXPECT_TRUE(WaitForCount(1, &count));
93 EXPECT_TRUE(thread->Stop());
hta@webrtc.org3168e532012-06-20 06:45:56 +000094 delete crit_sect;
95}
96
97bool LockUnlockRunFunction(void* obj) {
phoglund@webrtc.org99f7c912012-11-30 10:44:49 +000098 ProtectedCount* the_count = static_cast<ProtectedCount*>(obj);
hta@webrtc.org3168e532012-06-20 06:45:56 +000099 the_count->Increment();
100 SwitchProcess();
hta@webrtc.org3168e532012-06-20 06:45:56 +0000101 return true;
102}
103
andresp@webrtc.org7fb75ec2013-12-20 20:20:50 +0000104TEST_F(CritSectTest, ThreadWakesTwice) NO_THREAD_SAFETY_ANALYSIS {
phoglund@webrtc.org99f7c912012-11-30 10:44:49 +0000105 CriticalSectionWrapper* crit_sect =
106 CriticalSectionWrapper::CreateCriticalSection();
hta@webrtc.org3168e532012-06-20 06:45:56 +0000107 ProtectedCount count(crit_sect);
tommi@webrtc.org361981f2015-03-19 14:44:18 +0000108 rtc::scoped_ptr<ThreadWrapper> thread = ThreadWrapper::CreateThread(
109 &LockUnlockRunFunction, &count);
hta@webrtc.org3168e532012-06-20 06:45:56 +0000110 crit_sect->Enter(); // Make sure counter stays 0 until we wait for it.
pbos@webrtc.org86639732015-03-13 00:06:21 +0000111 ASSERT_TRUE(thread->Start());
hta@webrtc.org3168e532012-06-20 06:45:56 +0000112 crit_sect->Leave();
113
114 // The thread is capable of grabbing the lock multiple times,
115 // incrementing counter once each time.
116 // It's possible for the count to be incremented by more than 2.
117 EXPECT_TRUE(WaitForCount(2, &count));
118 EXPECT_LE(2, count.Count());
119
120 // The thread does not increment while lock is held.
121 crit_sect->Enter();
122 int count_before = count.Count();
123 for (int i = 0; i < 10; i++) {
124 SwitchProcess();
125 }
126 EXPECT_EQ(count_before, count.Count());
127 crit_sect->Leave();
128
hta@webrtc.org3168e532012-06-20 06:45:56 +0000129 SwitchProcess();
hta@webrtc.orga701c0e2013-04-09 12:36:28 +0000130 EXPECT_TRUE(WaitForCount(count_before + 1, &count));
hta@webrtc.org3168e532012-06-20 06:45:56 +0000131 EXPECT_TRUE(thread->Stop());
hta@webrtc.org3168e532012-06-20 06:45:56 +0000132 delete crit_sect;
133}
134
135} // anonymous namespace
136
137} // namespace webrtc