blob: 00b847ca1b8f84f7b9a9627e9ad73da998c8ead2 [file] [log] [blame]
Sebastian Janssonb55015e2019-04-09 13:44:04 +02001/*
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
Sebastian Janssonb55015e2019-04-09 13:44:04 +020016#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
23namespace webrtc {
24namespace {
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.
29class CompileTimeTestForGuardedBy {
30 public:
31 int CalledOnSequence() RTC_RUN_ON(sequence_checker_) { return guarded_; }
32
33 void CallMeFromSequence() {
34 RTC_DCHECK_RUN_ON(&sequence_checker_) << "Should be called on sequence";
35 guarded_ = 41;
36 }
37
38 private:
39 int guarded_ RTC_GUARDED_BY(sequence_checker_);
40 ::webrtc::SequenceChecker sequence_checker_;
41};
42
43void 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
63TEST(SequenceCheckerTest, CallsAllowedOnSameThread) {
64 SequenceChecker sequence_checker;
65 EXPECT_TRUE(sequence_checker.IsCurrent());
66}
67
68TEST(SequenceCheckerTest, DestructorAllowedOnDifferentThread) {
Mirko Bonadei317a1f02019-09-17 17:06:18 +020069 auto sequence_checker = std::make_unique<SequenceChecker>();
Sebastian Janssonb55015e2019-04-09 13:44:04 +020070 RunOnDifferentThread([&] {
71 // Verify that the destructor doesn't assert when called on a different
72 // thread.
73 sequence_checker.reset();
74 });
75}
76
77TEST(SequenceCheckerTest, Detach) {
78 SequenceChecker sequence_checker;
79 sequence_checker.Detach();
80 RunOnDifferentThread([&] { EXPECT_TRUE(sequence_checker.IsCurrent()); });
81}
82
83TEST(SequenceCheckerTest, DetachFromThreadAndUseOnTaskQueue) {
84 SequenceChecker sequence_checker;
85 sequence_checker.Detach();
86 TaskQueueForTest queue;
87 queue.SendTask([&] { EXPECT_TRUE(sequence_checker.IsCurrent()); });
88}
89
90TEST(SequenceCheckerTest, DetachFromTaskQueueAndUseOnThread) {
91 TaskQueueForTest queue;
92 queue.SendTask([] {
93 SequenceChecker sequence_checker;
94 sequence_checker.Detach();
95 RunOnDifferentThread([&] { EXPECT_TRUE(sequence_checker.IsCurrent()); });
96 });
97}
98
99TEST(SequenceCheckerTest, MethodNotAllowedOnDifferentThreadInDebug) {
100 SequenceChecker sequence_checker;
101 RunOnDifferentThread(
102 [&] { EXPECT_EQ(sequence_checker.IsCurrent(), !RTC_DCHECK_IS_ON); });
103}
104
105TEST(SequenceCheckerTest, MethodNotAllowedOnDifferentTaskQueueInDebug) {
106 SequenceChecker sequence_checker;
107 TaskQueueForTest queue;
108 queue.SendTask(
109 [&] { EXPECT_EQ(sequence_checker.IsCurrent(), !RTC_DCHECK_IS_ON); });
110}
111
112TEST(SequenceCheckerTest, DetachFromTaskQueueInDebug) {
113 SequenceChecker sequence_checker;
114 sequence_checker.Detach();
115
116 TaskQueueForTest queue1;
117 queue1.SendTask([&] { EXPECT_TRUE(sequence_checker.IsCurrent()); });
118
119 // IsCurrent should return false in debug builds after moving to
120 // another task queue.
121 TaskQueueForTest queue2;
122 queue2.SendTask(
123 [&] { EXPECT_EQ(sequence_checker.IsCurrent(), !RTC_DCHECK_IS_ON); });
124}
125
126class TestAnnotations {
127 public:
128 TestAnnotations() : test_var_(false) {}
129
130 void ModifyTestVar() {
131 RTC_DCHECK_RUN_ON(&checker_);
132 test_var_ = true;
133 }
134
135 private:
136 bool test_var_ RTC_GUARDED_BY(&checker_);
137 SequenceChecker checker_;
138};
139
140TEST(SequenceCheckerTest, TestAnnotations) {
141 TestAnnotations annotations;
142 annotations.ModifyTestVar();
143}
144
145#if GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
146
147void TestAnnotationsOnWrongQueue() {
148 TestAnnotations annotations;
149 TaskQueueForTest queue;
150 queue.SendTask([&] { annotations.ModifyTestVar(); });
151}
152
153#if RTC_DCHECK_IS_ON
154TEST(SequenceCheckerTest, TestAnnotationsOnWrongQueueDebug) {
155 ASSERT_DEATH({ TestAnnotationsOnWrongQueue(); }, "");
156}
157#else
158TEST(SequenceCheckerTest, TestAnnotationsOnWrongQueueRelease) {
159 TestAnnotationsOnWrongQueue();
160}
161#endif
162#endif // GTEST_HAS_DEATH_TEST
163} // namespace webrtc