blob: 85886483161b43520a600c81af2b49ecd3e12e33 [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
perkj9c16fe82016-07-12 15:04:07 -070011#include "webrtc/base/checks.h"
12#include "webrtc/base/constructormagic.h"
13#include "webrtc/base/platform_thread.h"
14#include "webrtc/base/sequenced_task_checker.h"
15#include "webrtc/base/task_queue.h"
kwibergac9f8762016-09-30 22:29:43 -070016#include "webrtc/test/gtest.h"
perkj9c16fe82016-07-12 15:04:07 -070017
18namespace rtc {
19
20namespace {
21// Calls SequencedTaskChecker::CalledSequentially on another thread.
22class CallCalledSequentiallyOnThread {
23 public:
24 CallCalledSequentiallyOnThread(bool expect_true,
25 SequencedTaskChecker* sequenced_task_checker)
26 : expect_true_(expect_true),
27 thread_has_run_event_(false, false),
28 thread_(&Run, this, "call_do_stuff_on_thread"),
29 sequenced_task_checker_(sequenced_task_checker) {
30 thread_.Start();
31 }
32 ~CallCalledSequentiallyOnThread() {
33 EXPECT_TRUE(thread_has_run_event_.Wait(1000));
34 thread_.Stop();
35 }
36
37 private:
38 static bool Run(void* obj) {
39 CallCalledSequentiallyOnThread* call_stuff_on_thread =
40 static_cast<CallCalledSequentiallyOnThread*>(obj);
41 EXPECT_EQ(
42 call_stuff_on_thread->expect_true_,
43 call_stuff_on_thread->sequenced_task_checker_->CalledSequentially());
44 call_stuff_on_thread->thread_has_run_event_.Set();
45 return false;
46 }
47
48 const bool expect_true_;
49 Event thread_has_run_event_;
50 PlatformThread thread_;
51 SequencedTaskChecker* const sequenced_task_checker_;
52
53 RTC_DISALLOW_COPY_AND_ASSIGN(CallCalledSequentiallyOnThread);
54};
55
56// Deletes SequencedTaskChecker on a different thread.
57class DeleteSequencedCheckerOnThread {
58 public:
59 explicit DeleteSequencedCheckerOnThread(
60 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker)
61 : thread_(&Run, this, "delete_sequenced_task_checker_on_thread"),
62 thread_has_run_event_(false, false),
63 sequenced_task_checker_(std::move(sequenced_task_checker)) {
64 thread_.Start();
65 }
66
67 ~DeleteSequencedCheckerOnThread() {
68 EXPECT_TRUE(thread_has_run_event_.Wait(1000));
69 thread_.Stop();
70 }
71
72 private:
73 static bool Run(void* obj) {
74 DeleteSequencedCheckerOnThread* instance =
75 static_cast<DeleteSequencedCheckerOnThread*>(obj);
76 instance->sequenced_task_checker_.reset();
77 instance->thread_has_run_event_.Set();
78 return false;
79 }
80
81 private:
82 PlatformThread thread_;
83 Event thread_has_run_event_;
84 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker_;
85
86 RTC_DISALLOW_COPY_AND_ASSIGN(DeleteSequencedCheckerOnThread);
87};
88
89void RunMethodOnDifferentThread(bool expect_true) {
90 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
91 new SequencedTaskChecker());
92
93 CallCalledSequentiallyOnThread call_on_thread(expect_true,
94 sequenced_task_checker.get());
95}
96
97void RunMethodOnDifferentTaskQueue(bool expect_true) {
98 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
99 new SequencedTaskChecker());
100
101 static const char kQueueName[] = "MethodNotAllowedOnDifferentTq";
102 TaskQueue queue(kQueueName);
103 Event done_event(false, false);
104 queue.PostTask([&sequenced_task_checker, &done_event, expect_true] {
105 if (expect_true)
106 EXPECT_TRUE(sequenced_task_checker->CalledSequentially());
107 else
108 EXPECT_FALSE(sequenced_task_checker->CalledSequentially());
109 done_event.Set();
110 });
111 EXPECT_TRUE(done_event.Wait(1000));
112}
113
114void DetachThenCallFromDifferentTaskQueue(bool expect_true) {
115 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
116 new SequencedTaskChecker());
117
118 sequenced_task_checker->Detach();
119
120 Event done_event(false, false);
121 TaskQueue queue1("DetachThenCallFromDifferentTaskQueueImpl1");
122 queue1.PostTask([&sequenced_task_checker, &done_event] {
123 EXPECT_TRUE(sequenced_task_checker->CalledSequentially());
124 done_event.Set();
125 });
126 EXPECT_TRUE(done_event.Wait(1000));
127
128 // CalledSequentially should return false in debug builds after moving to
129 // another task queue.
130 TaskQueue queue2("DetachThenCallFromDifferentTaskQueueImpl2");
131 queue2.PostTask([&sequenced_task_checker, &done_event, expect_true] {
132 if (expect_true)
133 EXPECT_TRUE(sequenced_task_checker->CalledSequentially());
134 else
135 EXPECT_FALSE(sequenced_task_checker->CalledSequentially());
136 done_event.Set();
137 });
138 EXPECT_TRUE(done_event.Wait(1000));
139}
140} // namespace
141
142TEST(SequencedTaskCheckerTest, CallsAllowedOnSameThread) {
143 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
144 new SequencedTaskChecker());
145
146 EXPECT_TRUE(sequenced_task_checker->CalledSequentially());
147
148 // Verify that the destructor doesn't assert.
149 sequenced_task_checker.reset();
150}
151
152TEST(SequencedTaskCheckerTest, DestructorAllowedOnDifferentThread) {
153 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
154 new SequencedTaskChecker());
155
156 // Verify that the destructor doesn't assert when called on a different
157 // thread.
158 DeleteSequencedCheckerOnThread delete_on_thread(
159 std::move(sequenced_task_checker));
160}
161
162TEST(SequencedTaskCheckerTest, DetachFromThread) {
163 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
164 new SequencedTaskChecker());
165
166 sequenced_task_checker->Detach();
167 CallCalledSequentiallyOnThread call_on_thread(true,
168 sequenced_task_checker.get());
169}
170
171TEST(SequencedTaskCheckerTest, DetachFromThreadAndUseOnTaskQueue) {
172 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
173 new SequencedTaskChecker());
174
175 sequenced_task_checker->Detach();
176 static const char kQueueName[] = "DetachFromThreadAndUseOnTaskQueue";
177 TaskQueue queue(kQueueName);
178 Event done_event(false, false);
179 queue.PostTask([&sequenced_task_checker, &done_event] {
180 EXPECT_TRUE(sequenced_task_checker->CalledSequentially());
181 done_event.Set();
182 });
183 EXPECT_TRUE(done_event.Wait(1000));
184}
185
186TEST(SequencedTaskCheckerTest, DetachFromTaskQueueAndUseOnThread) {
187 TaskQueue queue("DetachFromTaskQueueAndUseOnThread");
188 Event done_event(false, false);
189 queue.PostTask([&done_event] {
190 std::unique_ptr<SequencedTaskChecker> sequenced_task_checker(
191 new SequencedTaskChecker());
192
193 sequenced_task_checker->Detach();
194 CallCalledSequentiallyOnThread call_on_thread(true,
195 sequenced_task_checker.get());
196 done_event.Set();
197 });
198 EXPECT_TRUE(done_event.Wait(1000));
199}
200
kwiberg5377bc72016-10-04 13:46:56 -0700201#if RTC_DCHECK_IS_ON
perkj9c16fe82016-07-12 15:04:07 -0700202TEST(SequencedTaskCheckerTest, MethodNotAllowedOnDifferentThreadInDebug) {
203 RunMethodOnDifferentThread(false);
204}
205#else
206TEST(SequencedTaskCheckerTest, MethodAllowedOnDifferentThreadInRelease) {
207 RunMethodOnDifferentThread(true);
208}
209#endif
210
kwiberg5377bc72016-10-04 13:46:56 -0700211#if RTC_DCHECK_IS_ON
perkj9c16fe82016-07-12 15:04:07 -0700212TEST(SequencedTaskCheckerTest, MethodNotAllowedOnDifferentTaskQueueInDebug) {
213 RunMethodOnDifferentTaskQueue(false);
214}
215#else
216TEST(SequencedTaskCheckerTest, MethodAllowedOnDifferentTaskQueueInRelease) {
217 RunMethodOnDifferentTaskQueue(true);
218}
219#endif
220
kwiberg5377bc72016-10-04 13:46:56 -0700221#if RTC_DCHECK_IS_ON
perkj9c16fe82016-07-12 15:04:07 -0700222TEST(SequencedTaskCheckerTest, DetachFromTaskQueueInDebug) {
223 DetachThenCallFromDifferentTaskQueue(false);
224}
225#else
226TEST(SequencedTaskCheckerTest, DetachFromTaskQueueInRelease) {
227 DetachThenCallFromDifferentTaskQueue(true);
228}
229#endif
230
231class TestAnnotations {
232 public:
233 TestAnnotations() : test_var_(false) {}
234
235 void ModifyTestVar() {
236 RTC_DCHECK_CALLED_SEQUENTIALLY(&checker_);
237 test_var_ = true;
238 }
239
240 private:
241 bool test_var_ GUARDED_BY(&checker_);
242 SequencedTaskChecker checker_;
243};
244
245TEST(SequencedTaskCheckerTest, TestAnnotations) {
246 TestAnnotations annotations;
247 annotations.ModifyTestVar();
248}
249
250#if GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
251
252void TestAnnotationsOnWrongQueue() {
253 TestAnnotations annotations;
254 static const char kQueueName[] = "TestAnnotationsOnWrongQueueDebug";
255 TaskQueue queue(kQueueName);
256 Event done_event(false, false);
257 queue.PostTask([&annotations, &done_event] {
258 annotations.ModifyTestVar();
259 done_event.Set();
260 });
261 EXPECT_TRUE(done_event.Wait(1000));
262}
263
264#if RTC_DCHECK_IS_ON
265TEST(SequencedTaskCheckerTest, TestAnnotationsOnWrongQueueDebug) {
266 ASSERT_DEATH({ TestAnnotationsOnWrongQueue(); }, "");
267}
268#else
269TEST(SequencedTaskCheckerTest, TestAnnotationsOnWrongQueueRelease) {
270 TestAnnotationsOnWrongQueue();
271}
272#endif
273#endif // GTEST_HAS_DEATH_TEST
274} // namespace rtc