• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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