1 /*
2 * Copyright (c) 2016 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 #include "rtc_base/synchronization/sequence_checker.h"
12
13 #include <memory>
14 #include <utility>
15
16 #include "api/function_view.h"
17 #include "rtc_base/event.h"
18 #include "rtc_base/platform_thread.h"
19 #include "rtc_base/task_queue_for_test.h"
20 #include "rtc_base/thread_checker.h"
21 #include "test/gtest.h"
22
23 namespace webrtc {
24 namespace {
25
26 // This class is dead code, but its purpose is to make sure that
27 // SequenceChecker is compatible with the RTC_GUARDED_BY and RTC_RUN_ON
28 // attributes that are checked at compile-time.
29 class CompileTimeTestForGuardedBy {
30 public:
CalledOnSequence()31 int CalledOnSequence() RTC_RUN_ON(sequence_checker_) { return guarded_; }
32
CallMeFromSequence()33 void CallMeFromSequence() {
34 RTC_DCHECK_RUN_ON(&sequence_checker_);
35 guarded_ = 41;
36 }
37
38 private:
39 int guarded_ RTC_GUARDED_BY(sequence_checker_);
40 ::webrtc::SequenceChecker sequence_checker_;
41 };
42
RunOnDifferentThread(rtc::FunctionView<void ()> run)43 void RunOnDifferentThread(rtc::FunctionView<void()> run) {
44 struct Object {
45 static void Run(void* obj) {
46 auto* me = static_cast<Object*>(obj);
47 me->run();
48 me->thread_has_run_event.Set();
49 }
50
51 rtc::FunctionView<void()> run;
52 rtc::Event thread_has_run_event;
53 } object{run};
54
55 rtc::PlatformThread thread(&Object::Run, &object, "thread");
56 thread.Start();
57 EXPECT_TRUE(object.thread_has_run_event.Wait(1000));
58 thread.Stop();
59 }
60
61 } // namespace
62
TEST(SequenceCheckerTest,CallsAllowedOnSameThread)63 TEST(SequenceCheckerTest, CallsAllowedOnSameThread) {
64 SequenceChecker sequence_checker;
65 EXPECT_TRUE(sequence_checker.IsCurrent());
66 }
67
TEST(SequenceCheckerTest,DestructorAllowedOnDifferentThread)68 TEST(SequenceCheckerTest, DestructorAllowedOnDifferentThread) {
69 auto sequence_checker = std::make_unique<SequenceChecker>();
70 RunOnDifferentThread([&] {
71 // Verify that the destructor doesn't assert when called on a different
72 // thread.
73 sequence_checker.reset();
74 });
75 }
76
TEST(SequenceCheckerTest,Detach)77 TEST(SequenceCheckerTest, Detach) {
78 SequenceChecker sequence_checker;
79 sequence_checker.Detach();
80 RunOnDifferentThread([&] { EXPECT_TRUE(sequence_checker.IsCurrent()); });
81 }
82
TEST(SequenceCheckerTest,DetachFromThreadAndUseOnTaskQueue)83 TEST(SequenceCheckerTest, DetachFromThreadAndUseOnTaskQueue) {
84 SequenceChecker sequence_checker;
85 sequence_checker.Detach();
86 TaskQueueForTest queue;
87 queue.SendTask([&] { EXPECT_TRUE(sequence_checker.IsCurrent()); },
88 RTC_FROM_HERE);
89 }
90
TEST(SequenceCheckerTest,DetachFromTaskQueueAndUseOnThread)91 TEST(SequenceCheckerTest, DetachFromTaskQueueAndUseOnThread) {
92 TaskQueueForTest queue;
93 queue.SendTask(
94 [] {
95 SequenceChecker sequence_checker;
96 sequence_checker.Detach();
97 RunOnDifferentThread(
98 [&] { EXPECT_TRUE(sequence_checker.IsCurrent()); });
99 },
100 RTC_FROM_HERE);
101 }
102
TEST(SequenceCheckerTest,MethodNotAllowedOnDifferentThreadInDebug)103 TEST(SequenceCheckerTest, MethodNotAllowedOnDifferentThreadInDebug) {
104 SequenceChecker sequence_checker;
105 RunOnDifferentThread(
106 [&] { EXPECT_EQ(sequence_checker.IsCurrent(), !RTC_DCHECK_IS_ON); });
107 }
108
TEST(SequenceCheckerTest,MethodNotAllowedOnDifferentTaskQueueInDebug)109 TEST(SequenceCheckerTest, MethodNotAllowedOnDifferentTaskQueueInDebug) {
110 SequenceChecker sequence_checker;
111 TaskQueueForTest queue;
112 queue.SendTask(
113 [&] { EXPECT_EQ(sequence_checker.IsCurrent(), !RTC_DCHECK_IS_ON); },
114 RTC_FROM_HERE);
115 }
116
TEST(SequenceCheckerTest,DetachFromTaskQueueInDebug)117 TEST(SequenceCheckerTest, DetachFromTaskQueueInDebug) {
118 SequenceChecker sequence_checker;
119 sequence_checker.Detach();
120
121 TaskQueueForTest queue1;
122 queue1.SendTask([&] { EXPECT_TRUE(sequence_checker.IsCurrent()); },
123 RTC_FROM_HERE);
124
125 // IsCurrent should return false in debug builds after moving to
126 // another task queue.
127 TaskQueueForTest queue2;
128 queue2.SendTask(
129 [&] { EXPECT_EQ(sequence_checker.IsCurrent(), !RTC_DCHECK_IS_ON); },
130 RTC_FROM_HERE);
131 }
132
133 class TestAnnotations {
134 public:
TestAnnotations()135 TestAnnotations() : test_var_(false) {}
136
ModifyTestVar()137 void ModifyTestVar() {
138 RTC_DCHECK_RUN_ON(&checker_);
139 test_var_ = true;
140 }
141
142 private:
143 bool test_var_ RTC_GUARDED_BY(&checker_);
144 SequenceChecker checker_;
145 };
146
TEST(SequenceCheckerTest,TestAnnotations)147 TEST(SequenceCheckerTest, TestAnnotations) {
148 TestAnnotations annotations;
149 annotations.ModifyTestVar();
150 }
151
152 #if GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
153
TestAnnotationsOnWrongQueue()154 void TestAnnotationsOnWrongQueue() {
155 TestAnnotations annotations;
156 TaskQueueForTest queue;
157 queue.SendTask([&] { annotations.ModifyTestVar(); }, RTC_FROM_HERE);
158 }
159
160 #if RTC_DCHECK_IS_ON
161 // Note: Ending the test suite name with 'DeathTest' is important as it causes
162 // gtest to order this test before any other non-death-tests, to avoid potential
163 // global process state pollution such as shared worker threads being started
164 // (e.g. a side effect of calling InitCocoaMultiThreading() on Mac causes one or
165 // two additional threads to be created).
TEST(SequenceCheckerDeathTest,TestAnnotationsOnWrongQueueDebug)166 TEST(SequenceCheckerDeathTest, TestAnnotationsOnWrongQueueDebug) {
167 ASSERT_DEATH({ TestAnnotationsOnWrongQueue(); }, "");
168 }
169 #else
TEST(SequenceCheckerTest,TestAnnotationsOnWrongQueueRelease)170 TEST(SequenceCheckerTest, TestAnnotationsOnWrongQueueRelease) {
171 TestAnnotationsOnWrongQueue();
172 }
173 #endif
174 #endif // GTEST_HAS_DEATH_TEST
175 } // namespace webrtc
176