blob: 7b7247c64c015fad3f1677f8ac712afec9b89021 [file] [log] [blame]
perkj9c16fe82016-07-12 15:04:07 -07001/*
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 */
kwibergac9f8762016-09-30 22:29:43 -070010
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "rtc_base/sequenced_task_checker.h"
Tommi10b40ce2018-02-19 13:34:00 +010012
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020013#include "rtc_base/checks.h"
14#include "rtc_base/constructormagic.h"
Yves Gerey2e00abc2018-10-05 15:39:24 +020015#include "rtc_base/event.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020016#include "rtc_base/platform_thread.h"
17#include "rtc_base/task_queue.h"
Tommi10b40ce2018-02-19 13:34:00 +010018#include "rtc_base/thread_checker.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "test/gtest.h"
perkj9c16fe82016-07-12 15:04:07 -070020
21namespace rtc {
22
23namespace {
Tommi10b40ce2018-02-19 13:34:00 +010024
25// This class is dead code, but its purpose is to make sure that
26// SequencedTaskChecker is compatible with the RTC_GUARDED_BY and RTC_RUN_ON
27// attributes that are checked at compile-time.
28class CompileTimeTestForGuardedBy {
29 public:
Yves Gerey665174f2018-06-19 15:03:05 +020030 int CalledOnSequence() RTC_RUN_ON(sequence_checker_) { return guarded_; }
Tommi10b40ce2018-02-19 13:34:00 +010031
32 void CallMeFromSequence() {
Yves Gerey665174f2018-06-19 15:03:05 +020033 RTC_DCHECK_RUN_ON(&sequence_checker_) << "Should be called on sequence";
Tommi10b40ce2018-02-19 13:34:00 +010034 }
35
36 private:
37 int guarded_ RTC_GUARDED_BY(sequence_checker_);
38 rtc::SequencedTaskChecker sequence_checker_;
39};
40
perkj9c16fe82016-07-12 15:04:07 -070041// Calls SequencedTaskChecker::CalledSequentially on another thread.
42class CallCalledSequentiallyOnThread {
43 public:
44 CallCalledSequentiallyOnThread(bool expect_true,
45 SequencedTaskChecker* sequenced_task_checker)
46 : expect_true_(expect_true),
perkj9c16fe82016-07-12 15:04:07 -070047 thread_(&Run, this, "call_do_stuff_on_thread"),
48 sequenced_task_checker_(sequenced_task_checker) {
49 thread_.Start();
50 }
51 ~CallCalledSequentiallyOnThread() {
52 EXPECT_TRUE(thread_has_run_event_.Wait(1000));
53 thread_.Stop();
54 }
55
56 private:
tommi0f8b4032017-02-22 11:22:05 -080057 static void Run(void* obj) {
perkj9c16fe82016-07-12 15:04:07 -070058 CallCalledSequentiallyOnThread* call_stuff_on_thread =
59 static_cast<CallCalledSequentiallyOnThread*>(obj);
60 EXPECT_EQ(
61 call_stuff_on_thread->expect_true_,
62 call_stuff_on_thread->sequenced_task_checker_->CalledSequentially());
63 call_stuff_on_thread->thread_has_run_event_.Set();
perkj9c16fe82016-07-12 15:04:07 -070064 }
65
66 const bool expect_true_;
67 Event thread_has_run_event_;
68 PlatformThread thread_;
69 SequencedTaskChecker* const sequenced_task_checker_;
70
71 RTC_DISALLOW_COPY_AND_ASSIGN(CallCalledSequentiallyOnThread);
72};
73
74// Deletes SequencedTaskChecker on a different thread.
75class DeleteSequencedCheckerOnThread {
76 public:
77 explicit DeleteSequencedCheckerOnThread(
78 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker)
79 : thread_(&Run, this, "delete_sequenced_task_checker_on_thread"),
perkj9c16fe82016-07-12 15:04:07 -070080 sequenced_task_checker_(std::move(sequenced_task_checker)) {
81 thread_.Start();
82 }
83
84 ~DeleteSequencedCheckerOnThread() {
85 EXPECT_TRUE(thread_has_run_event_.Wait(1000));
86 thread_.Stop();
87 }
88
89 private:
90 static bool Run(void* obj) {
91 DeleteSequencedCheckerOnThread* instance =
92 static_cast<DeleteSequencedCheckerOnThread*>(obj);
93 instance->sequenced_task_checker_.reset();
94 instance->thread_has_run_event_.Set();
95 return false;
96 }
97
98 private:
99 PlatformThread thread_;
100 Event thread_has_run_event_;
101 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker_;
102
103 RTC_DISALLOW_COPY_AND_ASSIGN(DeleteSequencedCheckerOnThread);
104};
105
106void RunMethodOnDifferentThread(bool expect_true) {
107 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
108 new SequencedTaskChecker());
109
110 CallCalledSequentiallyOnThread call_on_thread(expect_true,
111 sequenced_task_checker.get());
112}
113
114void RunMethodOnDifferentTaskQueue(bool expect_true) {
115 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
116 new SequencedTaskChecker());
117
118 static const char kQueueName[] = "MethodNotAllowedOnDifferentTq";
119 TaskQueue queue(kQueueName);
Niels Möllerc572ff32018-11-07 08:43:50 +0100120 Event done_event;
perkj9c16fe82016-07-12 15:04:07 -0700121 queue.PostTask([&sequenced_task_checker, &done_event, expect_true] {
122 if (expect_true)
123 EXPECT_TRUE(sequenced_task_checker->CalledSequentially());
124 else
125 EXPECT_FALSE(sequenced_task_checker->CalledSequentially());
126 done_event.Set();
127 });
128 EXPECT_TRUE(done_event.Wait(1000));
129}
130
131void DetachThenCallFromDifferentTaskQueue(bool expect_true) {
132 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
133 new SequencedTaskChecker());
134
135 sequenced_task_checker->Detach();
136
Niels Möllerc572ff32018-11-07 08:43:50 +0100137 Event done_event;
perkj9c16fe82016-07-12 15:04:07 -0700138 TaskQueue queue1("DetachThenCallFromDifferentTaskQueueImpl1");
139 queue1.PostTask([&sequenced_task_checker, &done_event] {
140 EXPECT_TRUE(sequenced_task_checker->CalledSequentially());
141 done_event.Set();
142 });
143 EXPECT_TRUE(done_event.Wait(1000));
144
145 // CalledSequentially should return false in debug builds after moving to
146 // another task queue.
147 TaskQueue queue2("DetachThenCallFromDifferentTaskQueueImpl2");
148 queue2.PostTask([&sequenced_task_checker, &done_event, expect_true] {
149 if (expect_true)
150 EXPECT_TRUE(sequenced_task_checker->CalledSequentially());
151 else
152 EXPECT_FALSE(sequenced_task_checker->CalledSequentially());
153 done_event.Set();
154 });
155 EXPECT_TRUE(done_event.Wait(1000));
156}
157} // namespace
158
159TEST(SequencedTaskCheckerTest, CallsAllowedOnSameThread) {
160 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
161 new SequencedTaskChecker());
162
163 EXPECT_TRUE(sequenced_task_checker->CalledSequentially());
164
165 // Verify that the destructor doesn't assert.
166 sequenced_task_checker.reset();
167}
168
169TEST(SequencedTaskCheckerTest, DestructorAllowedOnDifferentThread) {
170 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
171 new SequencedTaskChecker());
172
173 // Verify that the destructor doesn't assert when called on a different
174 // thread.
175 DeleteSequencedCheckerOnThread delete_on_thread(
176 std::move(sequenced_task_checker));
177}
178
179TEST(SequencedTaskCheckerTest, DetachFromThread) {
180 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
181 new SequencedTaskChecker());
182
183 sequenced_task_checker->Detach();
184 CallCalledSequentiallyOnThread call_on_thread(true,
185 sequenced_task_checker.get());
186}
187
188TEST(SequencedTaskCheckerTest, DetachFromThreadAndUseOnTaskQueue) {
189 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
190 new SequencedTaskChecker());
191
192 sequenced_task_checker->Detach();
193 static const char kQueueName[] = "DetachFromThreadAndUseOnTaskQueue";
194 TaskQueue queue(kQueueName);
Niels Möllerc572ff32018-11-07 08:43:50 +0100195 Event done_event;
perkj9c16fe82016-07-12 15:04:07 -0700196 queue.PostTask([&sequenced_task_checker, &done_event] {
197 EXPECT_TRUE(sequenced_task_checker->CalledSequentially());
198 done_event.Set();
199 });
200 EXPECT_TRUE(done_event.Wait(1000));
201}
202
203TEST(SequencedTaskCheckerTest, DetachFromTaskQueueAndUseOnThread) {
204 TaskQueue queue("DetachFromTaskQueueAndUseOnThread");
Niels Möllerc572ff32018-11-07 08:43:50 +0100205 Event done_event;
perkj9c16fe82016-07-12 15:04:07 -0700206 queue.PostTask([&done_event] {
207 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
208 new SequencedTaskChecker());
209
210 sequenced_task_checker->Detach();
211 CallCalledSequentiallyOnThread call_on_thread(true,
212 sequenced_task_checker.get());
213 done_event.Set();
214 });
215 EXPECT_TRUE(done_event.Wait(1000));
216}
217
kwiberg5377bc72016-10-04 13:46:56 -0700218#if RTC_DCHECK_IS_ON
perkj9c16fe82016-07-12 15:04:07 -0700219TEST(SequencedTaskCheckerTest, MethodNotAllowedOnDifferentThreadInDebug) {
220 RunMethodOnDifferentThread(false);
221}
222#else
223TEST(SequencedTaskCheckerTest, MethodAllowedOnDifferentThreadInRelease) {
224 RunMethodOnDifferentThread(true);
225}
226#endif
227
kwiberg5377bc72016-10-04 13:46:56 -0700228#if RTC_DCHECK_IS_ON
perkj9c16fe82016-07-12 15:04:07 -0700229TEST(SequencedTaskCheckerTest, MethodNotAllowedOnDifferentTaskQueueInDebug) {
230 RunMethodOnDifferentTaskQueue(false);
231}
232#else
233TEST(SequencedTaskCheckerTest, MethodAllowedOnDifferentTaskQueueInRelease) {
234 RunMethodOnDifferentTaskQueue(true);
235}
236#endif
237
kwiberg5377bc72016-10-04 13:46:56 -0700238#if RTC_DCHECK_IS_ON
perkj9c16fe82016-07-12 15:04:07 -0700239TEST(SequencedTaskCheckerTest, DetachFromTaskQueueInDebug) {
240 DetachThenCallFromDifferentTaskQueue(false);
241}
242#else
243TEST(SequencedTaskCheckerTest, DetachFromTaskQueueInRelease) {
244 DetachThenCallFromDifferentTaskQueue(true);
245}
246#endif
247
248class TestAnnotations {
249 public:
250 TestAnnotations() : test_var_(false) {}
251
252 void ModifyTestVar() {
253 RTC_DCHECK_CALLED_SEQUENTIALLY(&checker_);
254 test_var_ = true;
255 }
256
257 private:
danilchap3c6abd22017-09-06 05:46:29 -0700258 bool test_var_ RTC_GUARDED_BY(&checker_);
perkj9c16fe82016-07-12 15:04:07 -0700259 SequencedTaskChecker checker_;
260};
261
262TEST(SequencedTaskCheckerTest, TestAnnotations) {
263 TestAnnotations annotations;
264 annotations.ModifyTestVar();
265}
266
267#if GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
268
269void TestAnnotationsOnWrongQueue() {
270 TestAnnotations annotations;
271 static const char kQueueName[] = "TestAnnotationsOnWrongQueueDebug";
272 TaskQueue queue(kQueueName);
Niels Möllerc572ff32018-11-07 08:43:50 +0100273 Event done_event;
perkj9c16fe82016-07-12 15:04:07 -0700274 queue.PostTask([&annotations, &done_event] {
275 annotations.ModifyTestVar();
276 done_event.Set();
277 });
278 EXPECT_TRUE(done_event.Wait(1000));
279}
280
281#if RTC_DCHECK_IS_ON
282TEST(SequencedTaskCheckerTest, TestAnnotationsOnWrongQueueDebug) {
283 ASSERT_DEATH({ TestAnnotationsOnWrongQueue(); }, "");
284}
285#else
286TEST(SequencedTaskCheckerTest, TestAnnotationsOnWrongQueueRelease) {
287 TestAnnotationsOnWrongQueue();
288}
289#endif
290#endif // GTEST_HAS_DEATH_TEST
291} // namespace rtc