blob: 1e62e9759b4751278bdd4a078c69d0bef54c63b3 [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;
Danil Chapovaloveb90e6f2019-10-15 10:04:57 +020087 queue.SendTask([&] { EXPECT_TRUE(sequence_checker.IsCurrent()); },
88 RTC_FROM_HERE);
Sebastian Janssonb55015e2019-04-09 13:44:04 +020089}
90
91TEST(SequenceCheckerTest, DetachFromTaskQueueAndUseOnThread) {
92 TaskQueueForTest queue;
Danil Chapovaloveb90e6f2019-10-15 10:04:57 +020093 queue.SendTask(
94 [] {
95 SequenceChecker sequence_checker;
96 sequence_checker.Detach();
97 RunOnDifferentThread(
98 [&] { EXPECT_TRUE(sequence_checker.IsCurrent()); });
99 },
100 RTC_FROM_HERE);
Sebastian Janssonb55015e2019-04-09 13:44:04 +0200101}
102
103TEST(SequenceCheckerTest, MethodNotAllowedOnDifferentThreadInDebug) {
104 SequenceChecker sequence_checker;
105 RunOnDifferentThread(
106 [&] { EXPECT_EQ(sequence_checker.IsCurrent(), !RTC_DCHECK_IS_ON); });
107}
108
109TEST(SequenceCheckerTest, MethodNotAllowedOnDifferentTaskQueueInDebug) {
110 SequenceChecker sequence_checker;
111 TaskQueueForTest queue;
112 queue.SendTask(
Danil Chapovaloveb90e6f2019-10-15 10:04:57 +0200113 [&] { EXPECT_EQ(sequence_checker.IsCurrent(), !RTC_DCHECK_IS_ON); },
114 RTC_FROM_HERE);
Sebastian Janssonb55015e2019-04-09 13:44:04 +0200115}
116
117TEST(SequenceCheckerTest, DetachFromTaskQueueInDebug) {
118 SequenceChecker sequence_checker;
119 sequence_checker.Detach();
120
121 TaskQueueForTest queue1;
Danil Chapovaloveb90e6f2019-10-15 10:04:57 +0200122 queue1.SendTask([&] { EXPECT_TRUE(sequence_checker.IsCurrent()); },
123 RTC_FROM_HERE);
Sebastian Janssonb55015e2019-04-09 13:44:04 +0200124
125 // IsCurrent should return false in debug builds after moving to
126 // another task queue.
127 TaskQueueForTest queue2;
128 queue2.SendTask(
Danil Chapovaloveb90e6f2019-10-15 10:04:57 +0200129 [&] { EXPECT_EQ(sequence_checker.IsCurrent(), !RTC_DCHECK_IS_ON); },
130 RTC_FROM_HERE);
Sebastian Janssonb55015e2019-04-09 13:44:04 +0200131}
132
133class TestAnnotations {
134 public:
135 TestAnnotations() : test_var_(false) {}
136
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
147TEST(SequenceCheckerTest, TestAnnotations) {
148 TestAnnotations annotations;
149 annotations.ModifyTestVar();
150}
151
152#if GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
153
154void TestAnnotationsOnWrongQueue() {
155 TestAnnotations annotations;
156 TaskQueueForTest queue;
Danil Chapovaloveb90e6f2019-10-15 10:04:57 +0200157 queue.SendTask([&] { annotations.ModifyTestVar(); }, RTC_FROM_HERE);
Sebastian Janssonb55015e2019-04-09 13:44:04 +0200158}
159
160#if RTC_DCHECK_IS_ON
161TEST(SequenceCheckerTest, TestAnnotationsOnWrongQueueDebug) {
162 ASSERT_DEATH({ TestAnnotationsOnWrongQueue(); }, "");
163}
164#else
165TEST(SequenceCheckerTest, TestAnnotationsOnWrongQueueRelease) {
166 TestAnnotationsOnWrongQueue();
167}
168#endif
169#endif // GTEST_HAS_DEATH_TEST
170} // namespace webrtc