blob: 96e655baad4f37c3706b23b72d14183ebfdf3826 [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"
15#include "rtc_base/platform_thread.h"
16#include "rtc_base/task_queue.h"
Tommi10b40ce2018-02-19 13:34:00 +010017#include "rtc_base/thread_checker.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "test/gtest.h"
perkj9c16fe82016-07-12 15:04:07 -070019
20namespace rtc {
21
22namespace {
Tommi10b40ce2018-02-19 13:34:00 +010023
24// This class is dead code, but its purpose is to make sure that
25// SequencedTaskChecker is compatible with the RTC_GUARDED_BY and RTC_RUN_ON
26// attributes that are checked at compile-time.
27class CompileTimeTestForGuardedBy {
28 public:
Yves Gerey665174f2018-06-19 15:03:05 +020029 int CalledOnSequence() RTC_RUN_ON(sequence_checker_) { return guarded_; }
Tommi10b40ce2018-02-19 13:34:00 +010030
31 void CallMeFromSequence() {
Yves Gerey665174f2018-06-19 15:03:05 +020032 RTC_DCHECK_RUN_ON(&sequence_checker_) << "Should be called on sequence";
Tommi10b40ce2018-02-19 13:34:00 +010033 }
34
35 private:
36 int guarded_ RTC_GUARDED_BY(sequence_checker_);
37 rtc::SequencedTaskChecker sequence_checker_;
38};
39
perkj9c16fe82016-07-12 15:04:07 -070040// Calls SequencedTaskChecker::CalledSequentially on another thread.
41class CallCalledSequentiallyOnThread {
42 public:
43 CallCalledSequentiallyOnThread(bool expect_true,
44 SequencedTaskChecker* sequenced_task_checker)
45 : expect_true_(expect_true),
46 thread_has_run_event_(false, false),
47 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"),
80 thread_has_run_event_(false, false),
81 sequenced_task_checker_(std::move(sequenced_task_checker)) {
82 thread_.Start();
83 }
84
85 ~DeleteSequencedCheckerOnThread() {
86 EXPECT_TRUE(thread_has_run_event_.Wait(1000));
87 thread_.Stop();
88 }
89
90 private:
91 static bool Run(void* obj) {
92 DeleteSequencedCheckerOnThread* instance =
93 static_cast<DeleteSequencedCheckerOnThread*>(obj);
94 instance->sequenced_task_checker_.reset();
95 instance->thread_has_run_event_.Set();
96 return false;
97 }
98
99 private:
100 PlatformThread thread_;
101 Event thread_has_run_event_;
102 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker_;
103
104 RTC_DISALLOW_COPY_AND_ASSIGN(DeleteSequencedCheckerOnThread);
105};
106
107void RunMethodOnDifferentThread(bool expect_true) {
108 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
109 new SequencedTaskChecker());
110
111 CallCalledSequentiallyOnThread call_on_thread(expect_true,
112 sequenced_task_checker.get());
113}
114
115void RunMethodOnDifferentTaskQueue(bool expect_true) {
116 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
117 new SequencedTaskChecker());
118
119 static const char kQueueName[] = "MethodNotAllowedOnDifferentTq";
120 TaskQueue queue(kQueueName);
121 Event done_event(false, false);
122 queue.PostTask([&sequenced_task_checker, &done_event, expect_true] {
123 if (expect_true)
124 EXPECT_TRUE(sequenced_task_checker->CalledSequentially());
125 else
126 EXPECT_FALSE(sequenced_task_checker->CalledSequentially());
127 done_event.Set();
128 });
129 EXPECT_TRUE(done_event.Wait(1000));
130}
131
132void DetachThenCallFromDifferentTaskQueue(bool expect_true) {
133 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
134 new SequencedTaskChecker());
135
136 sequenced_task_checker->Detach();
137
138 Event done_event(false, false);
139 TaskQueue queue1("DetachThenCallFromDifferentTaskQueueImpl1");
140 queue1.PostTask([&sequenced_task_checker, &done_event] {
141 EXPECT_TRUE(sequenced_task_checker->CalledSequentially());
142 done_event.Set();
143 });
144 EXPECT_TRUE(done_event.Wait(1000));
145
146 // CalledSequentially should return false in debug builds after moving to
147 // another task queue.
148 TaskQueue queue2("DetachThenCallFromDifferentTaskQueueImpl2");
149 queue2.PostTask([&sequenced_task_checker, &done_event, expect_true] {
150 if (expect_true)
151 EXPECT_TRUE(sequenced_task_checker->CalledSequentially());
152 else
153 EXPECT_FALSE(sequenced_task_checker->CalledSequentially());
154 done_event.Set();
155 });
156 EXPECT_TRUE(done_event.Wait(1000));
157}
158} // namespace
159
160TEST(SequencedTaskCheckerTest, CallsAllowedOnSameThread) {
161 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
162 new SequencedTaskChecker());
163
164 EXPECT_TRUE(sequenced_task_checker->CalledSequentially());
165
166 // Verify that the destructor doesn't assert.
167 sequenced_task_checker.reset();
168}
169
170TEST(SequencedTaskCheckerTest, DestructorAllowedOnDifferentThread) {
171 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
172 new SequencedTaskChecker());
173
174 // Verify that the destructor doesn't assert when called on a different
175 // thread.
176 DeleteSequencedCheckerOnThread delete_on_thread(
177 std::move(sequenced_task_checker));
178}
179
180TEST(SequencedTaskCheckerTest, DetachFromThread) {
181 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
182 new SequencedTaskChecker());
183
184 sequenced_task_checker->Detach();
185 CallCalledSequentiallyOnThread call_on_thread(true,
186 sequenced_task_checker.get());
187}
188
189TEST(SequencedTaskCheckerTest, DetachFromThreadAndUseOnTaskQueue) {
190 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
191 new SequencedTaskChecker());
192
193 sequenced_task_checker->Detach();
194 static const char kQueueName[] = "DetachFromThreadAndUseOnTaskQueue";
195 TaskQueue queue(kQueueName);
196 Event done_event(false, false);
197 queue.PostTask([&sequenced_task_checker, &done_event] {
198 EXPECT_TRUE(sequenced_task_checker->CalledSequentially());
199 done_event.Set();
200 });
201 EXPECT_TRUE(done_event.Wait(1000));
202}
203
204TEST(SequencedTaskCheckerTest, DetachFromTaskQueueAndUseOnThread) {
205 TaskQueue queue("DetachFromTaskQueueAndUseOnThread");
206 Event done_event(false, false);
207 queue.PostTask([&done_event] {
208 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
209 new SequencedTaskChecker());
210
211 sequenced_task_checker->Detach();
212 CallCalledSequentiallyOnThread call_on_thread(true,
213 sequenced_task_checker.get());
214 done_event.Set();
215 });
216 EXPECT_TRUE(done_event.Wait(1000));
217}
218
kwiberg5377bc72016-10-04 13:46:56 -0700219#if RTC_DCHECK_IS_ON
perkj9c16fe82016-07-12 15:04:07 -0700220TEST(SequencedTaskCheckerTest, MethodNotAllowedOnDifferentThreadInDebug) {
221 RunMethodOnDifferentThread(false);
222}
223#else
224TEST(SequencedTaskCheckerTest, MethodAllowedOnDifferentThreadInRelease) {
225 RunMethodOnDifferentThread(true);
226}
227#endif
228
kwiberg5377bc72016-10-04 13:46:56 -0700229#if RTC_DCHECK_IS_ON
perkj9c16fe82016-07-12 15:04:07 -0700230TEST(SequencedTaskCheckerTest, MethodNotAllowedOnDifferentTaskQueueInDebug) {
231 RunMethodOnDifferentTaskQueue(false);
232}
233#else
234TEST(SequencedTaskCheckerTest, MethodAllowedOnDifferentTaskQueueInRelease) {
235 RunMethodOnDifferentTaskQueue(true);
236}
237#endif
238
kwiberg5377bc72016-10-04 13:46:56 -0700239#if RTC_DCHECK_IS_ON
perkj9c16fe82016-07-12 15:04:07 -0700240TEST(SequencedTaskCheckerTest, DetachFromTaskQueueInDebug) {
241 DetachThenCallFromDifferentTaskQueue(false);
242}
243#else
244TEST(SequencedTaskCheckerTest, DetachFromTaskQueueInRelease) {
245 DetachThenCallFromDifferentTaskQueue(true);
246}
247#endif
248
249class TestAnnotations {
250 public:
251 TestAnnotations() : test_var_(false) {}
252
253 void ModifyTestVar() {
254 RTC_DCHECK_CALLED_SEQUENTIALLY(&checker_);
255 test_var_ = true;
256 }
257
258 private:
danilchap3c6abd22017-09-06 05:46:29 -0700259 bool test_var_ RTC_GUARDED_BY(&checker_);
perkj9c16fe82016-07-12 15:04:07 -0700260 SequencedTaskChecker checker_;
261};
262
263TEST(SequencedTaskCheckerTest, TestAnnotations) {
264 TestAnnotations annotations;
265 annotations.ModifyTestVar();
266}
267
268#if GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
269
270void TestAnnotationsOnWrongQueue() {
271 TestAnnotations annotations;
272 static const char kQueueName[] = "TestAnnotationsOnWrongQueueDebug";
273 TaskQueue queue(kQueueName);
274 Event done_event(false, false);
275 queue.PostTask([&annotations, &done_event] {
276 annotations.ModifyTestVar();
277 done_event.Set();
278 });
279 EXPECT_TRUE(done_event.Wait(1000));
280}
281
282#if RTC_DCHECK_IS_ON
283TEST(SequencedTaskCheckerTest, TestAnnotationsOnWrongQueueDebug) {
284 ASSERT_DEATH({ TestAnnotationsOnWrongQueue(); }, "");
285}
286#else
287TEST(SequencedTaskCheckerTest, TestAnnotationsOnWrongQueueRelease) {
288 TestAnnotationsOnWrongQueue();
289}
290#endif
291#endif // GTEST_HAS_DEATH_TEST
292} // namespace rtc