blob: b3df2fab8b5372bb576db30f71f5f5cac385841c [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
Yves Gerey3e707812018-11-28 16:47:49 +010013#include <memory>
14#include <utility>
15
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020016#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080017#include "rtc_base/constructor_magic.h"
Yves Gerey2e00abc2018-10-05 15:39:24 +020018#include "rtc_base/event.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "rtc_base/platform_thread.h"
20#include "rtc_base/task_queue.h"
Tommi10b40ce2018-02-19 13:34:00 +010021#include "rtc_base/thread_checker.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020022#include "test/gtest.h"
perkj9c16fe82016-07-12 15:04:07 -070023
24namespace rtc {
25
26namespace {
Tommi10b40ce2018-02-19 13:34:00 +010027
28// This class is dead code, but its purpose is to make sure that
29// SequencedTaskChecker is compatible with the RTC_GUARDED_BY and RTC_RUN_ON
30// attributes that are checked at compile-time.
31class CompileTimeTestForGuardedBy {
32 public:
Yves Gerey665174f2018-06-19 15:03:05 +020033 int CalledOnSequence() RTC_RUN_ON(sequence_checker_) { return guarded_; }
Tommi10b40ce2018-02-19 13:34:00 +010034
35 void CallMeFromSequence() {
Yves Gerey665174f2018-06-19 15:03:05 +020036 RTC_DCHECK_RUN_ON(&sequence_checker_) << "Should be called on sequence";
Tommi10b40ce2018-02-19 13:34:00 +010037 }
38
39 private:
40 int guarded_ RTC_GUARDED_BY(sequence_checker_);
41 rtc::SequencedTaskChecker sequence_checker_;
42};
43
perkj9c16fe82016-07-12 15:04:07 -070044// Calls SequencedTaskChecker::CalledSequentially on another thread.
45class CallCalledSequentiallyOnThread {
46 public:
47 CallCalledSequentiallyOnThread(bool expect_true,
48 SequencedTaskChecker* sequenced_task_checker)
49 : expect_true_(expect_true),
perkj9c16fe82016-07-12 15:04:07 -070050 thread_(&Run, this, "call_do_stuff_on_thread"),
51 sequenced_task_checker_(sequenced_task_checker) {
52 thread_.Start();
53 }
54 ~CallCalledSequentiallyOnThread() {
55 EXPECT_TRUE(thread_has_run_event_.Wait(1000));
56 thread_.Stop();
57 }
58
59 private:
tommi0f8b4032017-02-22 11:22:05 -080060 static void Run(void* obj) {
perkj9c16fe82016-07-12 15:04:07 -070061 CallCalledSequentiallyOnThread* call_stuff_on_thread =
62 static_cast<CallCalledSequentiallyOnThread*>(obj);
63 EXPECT_EQ(
64 call_stuff_on_thread->expect_true_,
65 call_stuff_on_thread->sequenced_task_checker_->CalledSequentially());
66 call_stuff_on_thread->thread_has_run_event_.Set();
perkj9c16fe82016-07-12 15:04:07 -070067 }
68
69 const bool expect_true_;
70 Event thread_has_run_event_;
71 PlatformThread thread_;
72 SequencedTaskChecker* const sequenced_task_checker_;
73
74 RTC_DISALLOW_COPY_AND_ASSIGN(CallCalledSequentiallyOnThread);
75};
76
77// Deletes SequencedTaskChecker on a different thread.
78class DeleteSequencedCheckerOnThread {
79 public:
80 explicit DeleteSequencedCheckerOnThread(
81 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker)
82 : thread_(&Run, this, "delete_sequenced_task_checker_on_thread"),
perkj9c16fe82016-07-12 15:04:07 -070083 sequenced_task_checker_(std::move(sequenced_task_checker)) {
84 thread_.Start();
85 }
86
87 ~DeleteSequencedCheckerOnThread() {
88 EXPECT_TRUE(thread_has_run_event_.Wait(1000));
89 thread_.Stop();
90 }
91
92 private:
93 static bool Run(void* obj) {
94 DeleteSequencedCheckerOnThread* instance =
95 static_cast<DeleteSequencedCheckerOnThread*>(obj);
96 instance->sequenced_task_checker_.reset();
97 instance->thread_has_run_event_.Set();
98 return false;
99 }
100
101 private:
102 PlatformThread thread_;
103 Event thread_has_run_event_;
104 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker_;
105
106 RTC_DISALLOW_COPY_AND_ASSIGN(DeleteSequencedCheckerOnThread);
107};
108
109void RunMethodOnDifferentThread(bool expect_true) {
110 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
111 new SequencedTaskChecker());
112
113 CallCalledSequentiallyOnThread call_on_thread(expect_true,
114 sequenced_task_checker.get());
115}
116
117void RunMethodOnDifferentTaskQueue(bool expect_true) {
118 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
119 new SequencedTaskChecker());
120
121 static const char kQueueName[] = "MethodNotAllowedOnDifferentTq";
122 TaskQueue queue(kQueueName);
Niels Möllerc572ff32018-11-07 08:43:50 +0100123 Event done_event;
perkj9c16fe82016-07-12 15:04:07 -0700124 queue.PostTask([&sequenced_task_checker, &done_event, expect_true] {
125 if (expect_true)
126 EXPECT_TRUE(sequenced_task_checker->CalledSequentially());
127 else
128 EXPECT_FALSE(sequenced_task_checker->CalledSequentially());
129 done_event.Set();
130 });
131 EXPECT_TRUE(done_event.Wait(1000));
132}
133
134void DetachThenCallFromDifferentTaskQueue(bool expect_true) {
135 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
136 new SequencedTaskChecker());
137
138 sequenced_task_checker->Detach();
139
Niels Möllerc572ff32018-11-07 08:43:50 +0100140 Event done_event;
perkj9c16fe82016-07-12 15:04:07 -0700141 TaskQueue queue1("DetachThenCallFromDifferentTaskQueueImpl1");
142 queue1.PostTask([&sequenced_task_checker, &done_event] {
143 EXPECT_TRUE(sequenced_task_checker->CalledSequentially());
144 done_event.Set();
145 });
146 EXPECT_TRUE(done_event.Wait(1000));
147
148 // CalledSequentially should return false in debug builds after moving to
149 // another task queue.
150 TaskQueue queue2("DetachThenCallFromDifferentTaskQueueImpl2");
151 queue2.PostTask([&sequenced_task_checker, &done_event, expect_true] {
152 if (expect_true)
153 EXPECT_TRUE(sequenced_task_checker->CalledSequentially());
154 else
155 EXPECT_FALSE(sequenced_task_checker->CalledSequentially());
156 done_event.Set();
157 });
158 EXPECT_TRUE(done_event.Wait(1000));
159}
160} // namespace
161
162TEST(SequencedTaskCheckerTest, CallsAllowedOnSameThread) {
163 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
164 new SequencedTaskChecker());
165
166 EXPECT_TRUE(sequenced_task_checker->CalledSequentially());
167
168 // Verify that the destructor doesn't assert.
169 sequenced_task_checker.reset();
170}
171
172TEST(SequencedTaskCheckerTest, DestructorAllowedOnDifferentThread) {
173 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
174 new SequencedTaskChecker());
175
176 // Verify that the destructor doesn't assert when called on a different
177 // thread.
178 DeleteSequencedCheckerOnThread delete_on_thread(
179 std::move(sequenced_task_checker));
180}
181
182TEST(SequencedTaskCheckerTest, DetachFromThread) {
183 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
184 new SequencedTaskChecker());
185
186 sequenced_task_checker->Detach();
187 CallCalledSequentiallyOnThread call_on_thread(true,
188 sequenced_task_checker.get());
189}
190
191TEST(SequencedTaskCheckerTest, DetachFromThreadAndUseOnTaskQueue) {
192 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
193 new SequencedTaskChecker());
194
195 sequenced_task_checker->Detach();
196 static const char kQueueName[] = "DetachFromThreadAndUseOnTaskQueue";
197 TaskQueue queue(kQueueName);
Niels Möllerc572ff32018-11-07 08:43:50 +0100198 Event done_event;
perkj9c16fe82016-07-12 15:04:07 -0700199 queue.PostTask([&sequenced_task_checker, &done_event] {
200 EXPECT_TRUE(sequenced_task_checker->CalledSequentially());
201 done_event.Set();
202 });
203 EXPECT_TRUE(done_event.Wait(1000));
204}
205
206TEST(SequencedTaskCheckerTest, DetachFromTaskQueueAndUseOnThread) {
207 TaskQueue queue("DetachFromTaskQueueAndUseOnThread");
Niels Möllerc572ff32018-11-07 08:43:50 +0100208 Event done_event;
perkj9c16fe82016-07-12 15:04:07 -0700209 queue.PostTask([&done_event] {
210 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
211 new SequencedTaskChecker());
212
213 sequenced_task_checker->Detach();
214 CallCalledSequentiallyOnThread call_on_thread(true,
215 sequenced_task_checker.get());
216 done_event.Set();
217 });
218 EXPECT_TRUE(done_event.Wait(1000));
219}
220
kwiberg5377bc72016-10-04 13:46:56 -0700221#if RTC_DCHECK_IS_ON
perkj9c16fe82016-07-12 15:04:07 -0700222TEST(SequencedTaskCheckerTest, MethodNotAllowedOnDifferentThreadInDebug) {
223 RunMethodOnDifferentThread(false);
224}
225#else
226TEST(SequencedTaskCheckerTest, MethodAllowedOnDifferentThreadInRelease) {
227 RunMethodOnDifferentThread(true);
228}
229#endif
230
kwiberg5377bc72016-10-04 13:46:56 -0700231#if RTC_DCHECK_IS_ON
perkj9c16fe82016-07-12 15:04:07 -0700232TEST(SequencedTaskCheckerTest, MethodNotAllowedOnDifferentTaskQueueInDebug) {
233 RunMethodOnDifferentTaskQueue(false);
234}
235#else
236TEST(SequencedTaskCheckerTest, MethodAllowedOnDifferentTaskQueueInRelease) {
237 RunMethodOnDifferentTaskQueue(true);
238}
239#endif
240
kwiberg5377bc72016-10-04 13:46:56 -0700241#if RTC_DCHECK_IS_ON
perkj9c16fe82016-07-12 15:04:07 -0700242TEST(SequencedTaskCheckerTest, DetachFromTaskQueueInDebug) {
243 DetachThenCallFromDifferentTaskQueue(false);
244}
245#else
246TEST(SequencedTaskCheckerTest, DetachFromTaskQueueInRelease) {
247 DetachThenCallFromDifferentTaskQueue(true);
248}
249#endif
250
251class TestAnnotations {
252 public:
253 TestAnnotations() : test_var_(false) {}
254
255 void ModifyTestVar() {
256 RTC_DCHECK_CALLED_SEQUENTIALLY(&checker_);
257 test_var_ = true;
258 }
259
260 private:
danilchap3c6abd22017-09-06 05:46:29 -0700261 bool test_var_ RTC_GUARDED_BY(&checker_);
perkj9c16fe82016-07-12 15:04:07 -0700262 SequencedTaskChecker checker_;
263};
264
265TEST(SequencedTaskCheckerTest, TestAnnotations) {
266 TestAnnotations annotations;
267 annotations.ModifyTestVar();
268}
269
270#if GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
271
272void TestAnnotationsOnWrongQueue() {
273 TestAnnotations annotations;
274 static const char kQueueName[] = "TestAnnotationsOnWrongQueueDebug";
275 TaskQueue queue(kQueueName);
Niels Möllerc572ff32018-11-07 08:43:50 +0100276 Event done_event;
perkj9c16fe82016-07-12 15:04:07 -0700277 queue.PostTask([&annotations, &done_event] {
278 annotations.ModifyTestVar();
279 done_event.Set();
280 });
281 EXPECT_TRUE(done_event.Wait(1000));
282}
283
284#if RTC_DCHECK_IS_ON
285TEST(SequencedTaskCheckerTest, TestAnnotationsOnWrongQueueDebug) {
286 ASSERT_DEATH({ TestAnnotationsOnWrongQueue(); }, "");
287}
288#else
289TEST(SequencedTaskCheckerTest, TestAnnotationsOnWrongQueueRelease) {
290 TestAnnotationsOnWrongQueue();
291}
292#endif
293#endif // GTEST_HAS_DEATH_TEST
294} // namespace rtc