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