1 // Copyright 2013 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/sequence_checker.h"
6
7 #include <stddef.h>
8
9 #include <memory>
10 #include <string>
11 #include <utility>
12
13 #include "base/functional/bind.h"
14 #include "base/functional/callback_helpers.h"
15 #include "base/sequence_checker_impl.h"
16 #include "base/sequence_token.h"
17 #include "base/task/single_thread_task_runner.h"
18 #include "base/task/thread_pool.h"
19 #include "base/test/bind.h"
20 #include "base/test/gtest_util.h"
21 #include "base/test/task_environment.h"
22 #include "base/threading/simple_thread.h"
23 #include "base/threading/thread_local.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25
26 namespace base::internal {
27
28 namespace {
29
30 // Runs a callback on another thread.
31 class RunCallbackThread : public SimpleThread {
32 public:
RunCallbackThread(OnceClosure callback)33 explicit RunCallbackThread(OnceClosure callback)
34 : SimpleThread("RunCallbackThread"), callback_(std::move(callback)) {
35 Start();
36 Join();
37 }
38 RunCallbackThread(const RunCallbackThread&) = delete;
39 RunCallbackThread& operator=(const RunCallbackThread&) = delete;
40
41 private:
42 // SimpleThread:
Run()43 void Run() override { std::move(callback_).Run(); }
44
45 OnceClosure callback_;
46 };
47
ExpectCalledOnValidSequence(SequenceCheckerImpl * sequence_checker)48 void ExpectCalledOnValidSequence(SequenceCheckerImpl* sequence_checker) {
49 ASSERT_TRUE(sequence_checker);
50
51 // This should bind |sequence_checker| to the current sequence if it wasn't
52 // already bound to a sequence.
53 EXPECT_TRUE(sequence_checker->CalledOnValidSequence());
54
55 // Since |sequence_checker| is now bound to the current sequence, another call
56 // to CalledOnValidSequence() should return true.
57 EXPECT_TRUE(sequence_checker->CalledOnValidSequence());
58 }
59
ExpectNotCalledOnValidSequence(SequenceCheckerImpl * sequence_checker)60 void ExpectNotCalledOnValidSequence(SequenceCheckerImpl* sequence_checker) {
61 ASSERT_TRUE(sequence_checker);
62 EXPECT_FALSE(sequence_checker->CalledOnValidSequence());
63 }
64
65 } // namespace
66
TEST(SequenceCheckerTest,NoTaskScope)67 TEST(SequenceCheckerTest, NoTaskScope) {
68 SequenceCheckerImpl sequence_checker;
69 EXPECT_TRUE(sequence_checker.CalledOnValidSequence());
70 }
71
TEST(SequenceCheckerTest,TaskScope)72 TEST(SequenceCheckerTest, TaskScope) {
73 TaskScope task_scope(SequenceToken::Create(),
74 /* is_thread_bound=*/false);
75 SequenceCheckerImpl sequence_checker;
76 EXPECT_TRUE(sequence_checker.CalledOnValidSequence());
77 }
78
TEST(SequenceCheckerTest,TaskScopeThreadBound)79 TEST(SequenceCheckerTest, TaskScopeThreadBound) {
80 TaskScope task_scope(SequenceToken::Create(),
81 /* is_thread_bound=*/true);
82 SequenceCheckerImpl sequence_checker;
83 EXPECT_TRUE(sequence_checker.CalledOnValidSequence());
84 }
85
TEST(SequenceCheckerTest,DifferentThreadNoTaskScope)86 TEST(SequenceCheckerTest, DifferentThreadNoTaskScope) {
87 SequenceCheckerImpl sequence_checker;
88 RunCallbackThread thread(
89 BindOnce(&ExpectNotCalledOnValidSequence, Unretained(&sequence_checker)));
90 }
91
TEST(SequenceCheckerTest,DifferentThreadDifferentSequenceToken)92 TEST(SequenceCheckerTest, DifferentThreadDifferentSequenceToken) {
93 SequenceCheckerImpl sequence_checker;
94 RunCallbackThread thread(BindLambdaForTesting([&]() {
95 TaskScope task_scope(SequenceToken::Create(),
96 /* is_thread_bound=*/false);
97 ExpectNotCalledOnValidSequence(&sequence_checker);
98 }));
99 }
100
TEST(SequenceCheckerTest,DifferentThreadDifferentSequenceTokenThreadBound)101 TEST(SequenceCheckerTest, DifferentThreadDifferentSequenceTokenThreadBound) {
102 SequenceCheckerImpl sequence_checker;
103 RunCallbackThread thread(BindLambdaForTesting([&]() {
104 TaskScope task_scope(SequenceToken::Create(),
105 /* is_thread_bound=*/true);
106 ExpectNotCalledOnValidSequence(&sequence_checker);
107 }));
108 }
109
TEST(SequenceCheckerTest,DifferentThreadSameSequenceToken)110 TEST(SequenceCheckerTest, DifferentThreadSameSequenceToken) {
111 const SequenceToken token = SequenceToken::Create();
112 TaskScope task_scope(token, /* is_thread_bound=*/false);
113 SequenceCheckerImpl sequence_checker;
114 RunCallbackThread thread(BindLambdaForTesting([&]() {
115 TaskScope task_scope(token, /* is_thread_bound=*/false);
116 ExpectCalledOnValidSequence(&sequence_checker);
117 }));
118 }
119
TEST(SequenceCheckerTest,DifferentThreadSameSequenceTokenThreadBound)120 TEST(SequenceCheckerTest, DifferentThreadSameSequenceTokenThreadBound) {
121 // Note: A callback running synchronously in `RunOrPostTask()` may have a
122 // non-thread-bound `TaskScope` associated with the same `SequenceToken` as
123 // another thread-bound `TaskScope`. This test recreates this case.
124 const SequenceToken token = SequenceToken::Create();
125 TaskScope task_scope(token, /* is_thread_bound=*/true);
126 SequenceCheckerImpl sequence_checker;
127 RunCallbackThread thread(BindLambdaForTesting([&]() {
128 TaskScope task_scope(token, /* is_thread_bound=*/false);
129 ExpectCalledOnValidSequence(&sequence_checker);
130 }));
131 }
132
TEST(SequenceCheckerTest,SameThreadDifferentSequenceToken)133 TEST(SequenceCheckerTest, SameThreadDifferentSequenceToken) {
134 std::unique_ptr<SequenceCheckerImpl> sequence_checker;
135
136 {
137 TaskScope task_scope(SequenceToken::Create(),
138 /* is_thread_bound=*/false);
139 sequence_checker = std::make_unique<SequenceCheckerImpl>();
140 }
141
142 {
143 // Different SequenceToken.
144 TaskScope task_scope(SequenceToken::Create(),
145 /* is_thread_bound=*/false);
146 EXPECT_FALSE(sequence_checker->CalledOnValidSequence());
147 }
148
149 // No explicit SequenceToken.
150 EXPECT_FALSE(sequence_checker->CalledOnValidSequence());
151 }
152
TEST(SequenceCheckerTest,DetachFromSequence)153 TEST(SequenceCheckerTest, DetachFromSequence) {
154 std::unique_ptr<SequenceCheckerImpl> sequence_checker;
155
156 {
157 TaskScope task_scope(SequenceToken::Create(),
158 /* is_thread_bound=*/false);
159 sequence_checker = std::make_unique<SequenceCheckerImpl>();
160 }
161
162 sequence_checker->DetachFromSequence();
163
164 {
165 // Verify that CalledOnValidSequence() returns true when called with
166 // a different sequence token after a call to DetachFromSequence().
167 TaskScope task_scope(SequenceToken::Create(),
168 /* is_thread_bound=*/false);
169 EXPECT_TRUE(sequence_checker->CalledOnValidSequence());
170 }
171 }
172
TEST(SequenceCheckerTest,DetachFromSequenceNoSequenceToken)173 TEST(SequenceCheckerTest, DetachFromSequenceNoSequenceToken) {
174 SequenceCheckerImpl sequence_checker;
175 sequence_checker.DetachFromSequence();
176
177 // Verify that CalledOnValidSequence() returns true when called on a
178 // different thread after a call to DetachFromSequence().
179 RunCallbackThread thread(
180 BindOnce(&ExpectCalledOnValidSequence, Unretained(&sequence_checker)));
181
182 EXPECT_FALSE(sequence_checker.CalledOnValidSequence());
183 }
184
TEST(SequenceCheckerTest,Move)185 TEST(SequenceCheckerTest, Move) {
186 SequenceCheckerImpl initial;
187 EXPECT_TRUE(initial.CalledOnValidSequence());
188
189 SequenceCheckerImpl move_constructed(std::move(initial));
190 EXPECT_TRUE(move_constructed.CalledOnValidSequence());
191
192 SequenceCheckerImpl move_assigned;
193 move_assigned = std::move(move_constructed);
194
195 // The two SequenceCheckerImpls moved from should be able to rebind to another
196 // sequence.
197 RunCallbackThread thread1(
198 BindOnce(&ExpectCalledOnValidSequence, Unretained(&initial)));
199 RunCallbackThread thread2(
200 BindOnce(&ExpectCalledOnValidSequence, Unretained(&move_constructed)));
201
202 // But the latest one shouldn't be able to run on another sequence.
203 RunCallbackThread thread(
204 BindOnce(&ExpectNotCalledOnValidSequence, Unretained(&move_assigned)));
205
206 EXPECT_TRUE(move_assigned.CalledOnValidSequence());
207 }
208
TEST(SequenceCheckerTest,MoveAssignIntoDetached)209 TEST(SequenceCheckerTest, MoveAssignIntoDetached) {
210 SequenceCheckerImpl initial;
211
212 SequenceCheckerImpl move_assigned;
213 move_assigned.DetachFromSequence();
214 move_assigned = std::move(initial);
215
216 // |initial| is detached after move.
217 RunCallbackThread thread1(
218 BindOnce(&ExpectCalledOnValidSequence, Unretained(&initial)));
219
220 // |move_assigned| should be associated with the main thread.
221 RunCallbackThread thread2(
222 BindOnce(&ExpectNotCalledOnValidSequence, Unretained(&move_assigned)));
223
224 EXPECT_TRUE(move_assigned.CalledOnValidSequence());
225 }
226
TEST(SequenceCheckerTest,MoveFromDetachedRebinds)227 TEST(SequenceCheckerTest, MoveFromDetachedRebinds) {
228 SequenceCheckerImpl initial;
229 initial.DetachFromSequence();
230
231 SequenceCheckerImpl moved_into(std::move(initial));
232
233 // |initial| is still detached after move.
234 RunCallbackThread thread1(
235 BindOnce(&ExpectCalledOnValidSequence, Unretained(&initial)));
236
237 // |moved_into| is bound to the current sequence as part of the move.
238 RunCallbackThread thread2(
239 BindOnce(&ExpectNotCalledOnValidSequence, Unretained(&moved_into)));
240 EXPECT_TRUE(moved_into.CalledOnValidSequence());
241 }
242
TEST(SequenceCheckerTest,MoveOffSequenceBanned)243 TEST(SequenceCheckerTest, MoveOffSequenceBanned) {
244 GTEST_FLAG_SET(death_test_style, "threadsafe");
245
246 SequenceCheckerImpl other_sequence;
247 other_sequence.DetachFromSequence();
248 RunCallbackThread thread(
249 BindOnce(&ExpectCalledOnValidSequence, Unretained(&other_sequence)));
250
251 EXPECT_DCHECK_DEATH(
252 SequenceCheckerImpl main_sequence(std::move(other_sequence)));
253 }
254
TEST(SequenceCheckerMacroTest,Macros)255 TEST(SequenceCheckerMacroTest, Macros) {
256 auto scope = std::make_unique<TaskScope>(SequenceToken::Create(),
257 /* is_thread_bound=*/false);
258 SEQUENCE_CHECKER(my_sequence_checker);
259
260 {
261 // Don't expect a DCHECK death when a SequenceChecker is used on the right
262 // sequence.
263 DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker);
264 }
265 scope.reset();
266
267 #if DCHECK_IS_ON()
268 // Expect DCHECK death when used on a different sequence.
269 EXPECT_DCHECK_DEATH(
270 { DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker); });
271 #else
272 // Happily no-ops on non-dcheck builds.
273 DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker);
274 #endif
275
276 DETACH_FROM_SEQUENCE(my_sequence_checker);
277
278 // Don't expect a DCHECK death when a SequenceChecker is used for the first
279 // time after having been detached.
280 DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker);
281 }
282
283 // Owns a SequenceCheckerImpl, and asserts that CalledOnValidSequence() is valid
284 // in ~SequenceCheckerOwner.
285 class SequenceCheckerOwner {
286 public:
SequenceCheckerOwner(SequenceCheckerImpl * other_checker)287 explicit SequenceCheckerOwner(SequenceCheckerImpl* other_checker)
288 : other_checker_(other_checker) {}
289 SequenceCheckerOwner(const SequenceCheckerOwner&) = delete;
290 SequenceCheckerOwner& operator=(const SequenceCheckerOwner&) = delete;
~SequenceCheckerOwner()291 ~SequenceCheckerOwner() {
292 // Check passes on TLS destruction.
293 EXPECT_TRUE(checker_.CalledOnValidSequence());
294
295 // Check also passes on TLS destruction after move assignment.
296 *other_checker_ = std::move(checker_);
297 EXPECT_TRUE(other_checker_->CalledOnValidSequence());
298 }
299
300 private:
301 SequenceCheckerImpl checker_;
302 raw_ptr<SequenceCheckerImpl> other_checker_;
303 };
304
305 // Verifies SequenceCheckerImpl::CalledOnValidSequence() returns true if called
306 // during thread destruction.
TEST(SequenceCheckerTest,FromThreadDestruction)307 TEST(SequenceCheckerTest, FromThreadDestruction) {
308 SequenceChecker::EnableStackLogging();
309
310 SequenceCheckerImpl other_checker;
311 ThreadLocalOwnedPointer<SequenceCheckerOwner> thread_local_owner;
312 {
313 test::TaskEnvironment task_environment;
314 auto task_runner = ThreadPool::CreateSequencedTaskRunner({});
315 task_runner->PostTask(
316 FROM_HERE, BindLambdaForTesting([&]() {
317 thread_local_owner.Set(
318 std::make_unique<SequenceCheckerOwner>(&other_checker));
319 }));
320 task_runner = nullptr;
321 task_environment.RunUntilIdle();
322 }
323 }
324
325 } // namespace base::internal
326