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/synchronization/lock.h"
18 #include "base/synchronization/lock_subtle.h"
19 #include "base/task/single_thread_task_runner.h"
20 #include "base/task/thread_pool.h"
21 #include "base/test/bind.h"
22 #include "base/test/gtest_util.h"
23 #include "base/test/task_environment.h"
24 #include "base/threading/simple_thread.h"
25 #include "base/threading/thread_local.h"
26 #include "testing/gtest/include/gtest/gtest.h"
27
28 namespace base::internal {
29
30 namespace {
31
32 // Runs a callback on another thread.
33 class RunCallbackThread : public SimpleThread {
34 public:
RunCallbackThread(OnceClosure callback)35 explicit RunCallbackThread(OnceClosure callback)
36 : SimpleThread("RunCallbackThread"), callback_(std::move(callback)) {
37 Start();
38 Join();
39 }
40 RunCallbackThread(const RunCallbackThread&) = delete;
41 RunCallbackThread& operator=(const RunCallbackThread&) = delete;
42
43 private:
44 // SimpleThread:
Run()45 void Run() override { std::move(callback_).Run(); }
46
47 OnceClosure callback_;
48 };
49
ExpectCalledOnValidSequence(SequenceCheckerImpl * sequence_checker)50 void ExpectCalledOnValidSequence(SequenceCheckerImpl* sequence_checker) {
51 ASSERT_TRUE(sequence_checker);
52
53 // This should bind |sequence_checker| to the current sequence if it wasn't
54 // already bound to a sequence.
55 EXPECT_TRUE(sequence_checker->CalledOnValidSequence());
56
57 // Since |sequence_checker| is now bound to the current sequence, another call
58 // to CalledOnValidSequence() should return true.
59 EXPECT_TRUE(sequence_checker->CalledOnValidSequence());
60 }
61
ExpectNotCalledOnValidSequence(SequenceCheckerImpl * sequence_checker)62 void ExpectNotCalledOnValidSequence(SequenceCheckerImpl* sequence_checker) {
63 ASSERT_TRUE(sequence_checker);
64 EXPECT_FALSE(sequence_checker->CalledOnValidSequence());
65 }
66
67 } // namespace
68
TEST(SequenceCheckerTest,NoTaskScope)69 TEST(SequenceCheckerTest, NoTaskScope) {
70 SequenceCheckerImpl sequence_checker;
71 EXPECT_TRUE(sequence_checker.CalledOnValidSequence());
72 }
73
TEST(SequenceCheckerTest,TaskScope)74 TEST(SequenceCheckerTest, TaskScope) {
75 TaskScope task_scope(SequenceToken::Create(),
76 /* is_thread_bound=*/false);
77 SequenceCheckerImpl sequence_checker;
78 EXPECT_TRUE(sequence_checker.CalledOnValidSequence());
79 }
80
TEST(SequenceCheckerTest,TaskScopeThreadBound)81 TEST(SequenceCheckerTest, TaskScopeThreadBound) {
82 TaskScope task_scope(SequenceToken::Create(),
83 /* is_thread_bound=*/true);
84 SequenceCheckerImpl sequence_checker;
85 EXPECT_TRUE(sequence_checker.CalledOnValidSequence());
86 }
87
TEST(SequenceCheckerTest,DifferentThreadNoTaskScope)88 TEST(SequenceCheckerTest, DifferentThreadNoTaskScope) {
89 SequenceCheckerImpl sequence_checker;
90 RunCallbackThread thread(
91 BindOnce(&ExpectNotCalledOnValidSequence, Unretained(&sequence_checker)));
92 }
93
TEST(SequenceCheckerTest,DifferentThreadDifferentSequenceToken)94 TEST(SequenceCheckerTest, DifferentThreadDifferentSequenceToken) {
95 SequenceCheckerImpl sequence_checker;
96 RunCallbackThread thread(BindLambdaForTesting([&] {
97 TaskScope task_scope(SequenceToken::Create(),
98 /* is_thread_bound=*/false);
99 ExpectNotCalledOnValidSequence(&sequence_checker);
100 }));
101 }
102
TEST(SequenceCheckerTest,DifferentThreadDifferentSequenceTokenThreadBound)103 TEST(SequenceCheckerTest, DifferentThreadDifferentSequenceTokenThreadBound) {
104 SequenceCheckerImpl sequence_checker;
105 RunCallbackThread thread(BindLambdaForTesting([&] {
106 TaskScope task_scope(SequenceToken::Create(),
107 /* is_thread_bound=*/true);
108 ExpectNotCalledOnValidSequence(&sequence_checker);
109 }));
110 }
111
TEST(SequenceCheckerTest,DifferentThreadSameSequenceToken)112 TEST(SequenceCheckerTest, DifferentThreadSameSequenceToken) {
113 const SequenceToken token = SequenceToken::Create();
114 TaskScope task_scope(token, /* is_thread_bound=*/false);
115 SequenceCheckerImpl sequence_checker;
116 RunCallbackThread thread(BindLambdaForTesting([&] {
117 TaskScope task_scope(token, /* is_thread_bound=*/false);
118 ExpectCalledOnValidSequence(&sequence_checker);
119 }));
120 }
121
TEST(SequenceCheckerTest,DifferentThreadSameSequenceTokenThreadBound)122 TEST(SequenceCheckerTest, DifferentThreadSameSequenceTokenThreadBound) {
123 // Note: A callback running synchronously in `RunOrPostTask()` may have a
124 // non-thread-bound `TaskScope` associated with the same `SequenceToken` as
125 // another thread-bound `TaskScope`. This test recreates this case.
126 const SequenceToken token = SequenceToken::Create();
127 TaskScope task_scope(token, /* is_thread_bound=*/true);
128 SequenceCheckerImpl sequence_checker;
129 RunCallbackThread thread(BindLambdaForTesting([&] {
130 TaskScope task_scope(token, /* is_thread_bound=*/false);
131 ExpectCalledOnValidSequence(&sequence_checker);
132 }));
133 }
134
TEST(SequenceCheckerTest,SameThreadDifferentSequenceToken)135 TEST(SequenceCheckerTest, SameThreadDifferentSequenceToken) {
136 std::unique_ptr<SequenceCheckerImpl> sequence_checker;
137
138 {
139 TaskScope task_scope(SequenceToken::Create(),
140 /* is_thread_bound=*/false);
141 sequence_checker = std::make_unique<SequenceCheckerImpl>();
142 }
143
144 {
145 // Different SequenceToken.
146 TaskScope task_scope(SequenceToken::Create(),
147 /* is_thread_bound=*/false);
148 EXPECT_FALSE(sequence_checker->CalledOnValidSequence());
149 }
150
151 // No explicit SequenceToken.
152 EXPECT_FALSE(sequence_checker->CalledOnValidSequence());
153 }
154
TEST(SequenceCheckerTest,DetachFromSequence)155 TEST(SequenceCheckerTest, DetachFromSequence) {
156 std::unique_ptr<SequenceCheckerImpl> sequence_checker;
157
158 {
159 TaskScope task_scope(SequenceToken::Create(),
160 /* is_thread_bound=*/false);
161 sequence_checker = std::make_unique<SequenceCheckerImpl>();
162 }
163
164 sequence_checker->DetachFromSequence();
165
166 {
167 // Verify that CalledOnValidSequence() returns true when called with
168 // a different sequence token after a call to DetachFromSequence().
169 TaskScope task_scope(SequenceToken::Create(),
170 /* is_thread_bound=*/false);
171 EXPECT_TRUE(sequence_checker->CalledOnValidSequence());
172 }
173 }
174
TEST(SequenceCheckerTest,DetachFromSequenceNoSequenceToken)175 TEST(SequenceCheckerTest, DetachFromSequenceNoSequenceToken) {
176 SequenceCheckerImpl sequence_checker;
177 sequence_checker.DetachFromSequence();
178
179 // Verify that CalledOnValidSequence() returns true when called on a
180 // different thread after a call to DetachFromSequence().
181 RunCallbackThread thread(
182 BindOnce(&ExpectCalledOnValidSequence, Unretained(&sequence_checker)));
183
184 EXPECT_FALSE(sequence_checker.CalledOnValidSequence());
185 }
186
TEST(SequenceCheckerTest,Move)187 TEST(SequenceCheckerTest, Move) {
188 SequenceCheckerImpl initial;
189 EXPECT_TRUE(initial.CalledOnValidSequence());
190
191 SequenceCheckerImpl move_constructed(std::move(initial));
192 EXPECT_TRUE(move_constructed.CalledOnValidSequence());
193
194 SequenceCheckerImpl move_assigned;
195 move_assigned = std::move(move_constructed);
196
197 // The two SequenceCheckerImpls moved from should be able to rebind to another
198 // sequence.
199 RunCallbackThread thread1(
200 BindOnce(&ExpectCalledOnValidSequence, Unretained(&initial)));
201 RunCallbackThread thread2(
202 BindOnce(&ExpectCalledOnValidSequence, Unretained(&move_constructed)));
203
204 // But the latest one shouldn't be able to run on another sequence.
205 RunCallbackThread thread(
206 BindOnce(&ExpectNotCalledOnValidSequence, Unretained(&move_assigned)));
207
208 EXPECT_TRUE(move_assigned.CalledOnValidSequence());
209 }
210
TEST(SequenceCheckerTest,MoveAssignIntoDetached)211 TEST(SequenceCheckerTest, MoveAssignIntoDetached) {
212 SequenceCheckerImpl initial;
213
214 SequenceCheckerImpl move_assigned;
215 move_assigned.DetachFromSequence();
216 move_assigned = std::move(initial);
217
218 // |initial| is detached after move.
219 RunCallbackThread thread1(
220 BindOnce(&ExpectCalledOnValidSequence, Unretained(&initial)));
221
222 // |move_assigned| should be associated with the main thread.
223 RunCallbackThread thread2(
224 BindOnce(&ExpectNotCalledOnValidSequence, Unretained(&move_assigned)));
225
226 EXPECT_TRUE(move_assigned.CalledOnValidSequence());
227 }
228
TEST(SequenceCheckerTest,MoveFromDetachedRebinds)229 TEST(SequenceCheckerTest, MoveFromDetachedRebinds) {
230 SequenceCheckerImpl initial;
231 initial.DetachFromSequence();
232
233 SequenceCheckerImpl moved_into(std::move(initial));
234
235 // |initial| is still detached after move.
236 RunCallbackThread thread1(
237 BindOnce(&ExpectCalledOnValidSequence, Unretained(&initial)));
238
239 // |moved_into| is bound to the current sequence as part of the move.
240 RunCallbackThread thread2(
241 BindOnce(&ExpectNotCalledOnValidSequence, Unretained(&moved_into)));
242 EXPECT_TRUE(moved_into.CalledOnValidSequence());
243 }
244
TEST(SequenceCheckerTest,MoveOffSequenceBanned)245 TEST(SequenceCheckerTest, MoveOffSequenceBanned) {
246 GTEST_FLAG_SET(death_test_style, "threadsafe");
247
248 SequenceCheckerImpl other_sequence;
249 other_sequence.DetachFromSequence();
250 RunCallbackThread thread(
251 BindOnce(&ExpectCalledOnValidSequence, Unretained(&other_sequence)));
252
253 EXPECT_DCHECK_DEATH(
254 SequenceCheckerImpl main_sequence(std::move(other_sequence)));
255 }
256
TEST(SequenceCheckerMacroTest,Macros)257 TEST(SequenceCheckerMacroTest, Macros) {
258 auto scope = std::make_unique<TaskScope>(SequenceToken::Create(),
259 /* is_thread_bound=*/false);
260 SEQUENCE_CHECKER(my_sequence_checker);
261
262 {
263 // Don't expect a DCHECK death when a SequenceChecker is used on the right
264 // sequence.
265 DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker);
266 }
267 scope.reset();
268
269 #if DCHECK_IS_ON()
270 // Expect DCHECK death when used on a different sequence.
271 EXPECT_DCHECK_DEATH(
272 { DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker); });
273 #else
274 // Happily no-ops on non-dcheck builds.
275 DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker);
276 #endif
277
278 DETACH_FROM_SEQUENCE(my_sequence_checker);
279
280 // Don't expect a DCHECK death when a SequenceChecker is used for the first
281 // time after having been detached.
282 DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker);
283 }
284
285 // Owns a SequenceCheckerImpl, and asserts that CalledOnValidSequence() is valid
286 // in ~SequenceCheckerOwner.
287 class SequenceCheckerOwner {
288 public:
SequenceCheckerOwner(SequenceCheckerImpl * other_checker)289 explicit SequenceCheckerOwner(SequenceCheckerImpl* other_checker)
290 : other_checker_(other_checker) {}
291 SequenceCheckerOwner(const SequenceCheckerOwner&) = delete;
292 SequenceCheckerOwner& operator=(const SequenceCheckerOwner&) = delete;
~SequenceCheckerOwner()293 ~SequenceCheckerOwner() {
294 // Check passes on TLS destruction.
295 EXPECT_TRUE(checker_.CalledOnValidSequence());
296
297 // Check also passes on TLS destruction after move assignment.
298 *other_checker_ = std::move(checker_);
299 EXPECT_TRUE(other_checker_->CalledOnValidSequence());
300 }
301
302 private:
303 SequenceCheckerImpl checker_;
304 raw_ptr<SequenceCheckerImpl> other_checker_;
305 };
306
307 // Verifies SequenceCheckerImpl::CalledOnValidSequence() returns true if called
308 // during thread destruction.
TEST(SequenceCheckerTest,FromThreadDestruction)309 TEST(SequenceCheckerTest, FromThreadDestruction) {
310 SequenceChecker::EnableStackLogging();
311
312 SequenceCheckerImpl other_checker;
313 ThreadLocalOwnedPointer<SequenceCheckerOwner> thread_local_owner;
314 {
315 test::TaskEnvironment task_environment;
316 auto task_runner = ThreadPool::CreateSequencedTaskRunner({});
317 task_runner->PostTask(
318 FROM_HERE, BindLambdaForTesting([&] {
319 thread_local_owner.Set(
320 std::make_unique<SequenceCheckerOwner>(&other_checker));
321 }));
322 task_runner = nullptr;
323 task_environment.RunUntilIdle();
324 }
325 }
326
327 // Verifies sequence checking while holding the same locks from different
328 // sequences.
329 //
330 // Note: This is only supported in DCHECK builds.
331 #if DCHECK_IS_ON()
TEST(SequenceCheckerTest,LockBasic)332 TEST(SequenceCheckerTest, LockBasic) {
333 test::TaskEnvironment task_environment;
334 WaitableEvent thread_pool_done;
335 Lock lock;
336
337 // Create sequence checker while holding lock.
338 ReleasableAutoLock releasable_auto_lock(&lock,
339 subtle::LockTracking::kEnabled);
340 SequenceCheckerImpl sequence_checker;
341 releasable_auto_lock.Release();
342
343 ThreadPool::PostTask(BindLambdaForTesting([&] {
344 // Check sequencing while holding the lock.
345 {
346 AutoLock auto_lock(lock, subtle::LockTracking::kEnabled);
347 EXPECT_TRUE(sequence_checker.CalledOnValidSequence());
348 }
349
350 thread_pool_done.Signal();
351 }));
352
353 thread_pool_done.Wait();
354
355 // Check sequencing from the creation sequence, without holding the lock.
356 // Sequencing is *not* valid because sequencing now depends on the lock.
357 EXPECT_FALSE(sequence_checker.CalledOnValidSequence());
358
359 // Check sequencing from the creation sequence while holding the lock.
360 {
361 AutoLock auto_lock(lock, subtle::LockTracking::kEnabled);
362 EXPECT_TRUE(sequence_checker.CalledOnValidSequence());
363 }
364 }
365
TEST(SequenceCheckerTest,ManyLocks)366 TEST(SequenceCheckerTest, ManyLocks) {
367 test::TaskEnvironment task_environment;
368 WaitableEvent thread_pool_done;
369 Lock lock_a;
370 Lock lock_b;
371 Lock lock_c;
372
373 ReleasableAutoLock releasable_auto_lock_a(&lock_a,
374 subtle::LockTracking::kEnabled);
375 ReleasableAutoLock releasable_auto_lock_b(&lock_b,
376 subtle::LockTracking::kEnabled);
377 ReleasableAutoLock releasable_auto_lock_c(&lock_c,
378 subtle::LockTracking::kEnabled);
379 SequenceCheckerImpl sequence_checker;
380 releasable_auto_lock_c.Release();
381 releasable_auto_lock_b.Release();
382 releasable_auto_lock_a.Release();
383
384 ThreadPool::PostTask(BindLambdaForTesting([&] {
385 {
386 AutoLock auto_lock_a(lock_a, subtle::LockTracking::kEnabled);
387 AutoLock auto_lock_b(lock_b, subtle::LockTracking::kEnabled);
388 AutoLock auto_lock_c(lock_c, subtle::LockTracking::kEnabled);
389 EXPECT_TRUE(sequence_checker.CalledOnValidSequence());
390 }
391
392 {
393 AutoLock auto_lock_a(lock_a, subtle::LockTracking::kEnabled);
394 AutoLock auto_lock_b(lock_b, subtle::LockTracking::kEnabled);
395 EXPECT_TRUE(sequence_checker.CalledOnValidSequence());
396 }
397
398 {
399 AutoLock auto_lock_c(lock_c, subtle::LockTracking::kEnabled);
400 EXPECT_FALSE(sequence_checker.CalledOnValidSequence());
401 }
402
403 {
404 AutoLock auto_lock_b(lock_b, subtle::LockTracking::kEnabled);
405 EXPECT_TRUE(sequence_checker.CalledOnValidSequence());
406 }
407
408 {
409 AutoLock auto_lock_b(lock_a, subtle::LockTracking::kEnabled);
410 EXPECT_FALSE(sequence_checker.CalledOnValidSequence());
411 }
412
413 thread_pool_done.Signal();
414 }));
415
416 thread_pool_done.Wait();
417
418 EXPECT_FALSE(sequence_checker.CalledOnValidSequence());
419 }
420
TEST(SequenceCheckerTest,LockAndSequence)421 TEST(SequenceCheckerTest, LockAndSequence) {
422 test::TaskEnvironment task_environment;
423 WaitableEvent thread_pool_done;
424 Lock lock;
425
426 // Create sequence checker while holding lock.
427 ReleasableAutoLock releasable_auto_lock(&lock,
428 subtle::LockTracking::kEnabled);
429 SequenceCheckerImpl sequence_checker;
430 releasable_auto_lock.Release();
431
432 // Check sequencing without holding the lock.
433 EXPECT_TRUE(sequence_checker.CalledOnValidSequence());
434
435 ThreadPool::PostTask(BindLambdaForTesting([&] {
436 // Check sequencing while holding the lock. This is not valid because
437 // `CalledOnValidSequence()` previously returned true while the lock wasn't
438 // held.
439 {
440 AutoLock auto_lock(lock, subtle::LockTracking::kEnabled);
441 EXPECT_FALSE(sequence_checker.CalledOnValidSequence());
442 }
443
444 thread_pool_done.Signal();
445 }));
446
447 thread_pool_done.Wait();
448 }
449
TEST(SequenceCheckerTest,LockDetachFromSequence)450 TEST(SequenceCheckerTest, LockDetachFromSequence) {
451 test::TaskEnvironment task_environment;
452 WaitableEvent thread_pool_done;
453 Lock lock;
454
455 // Create sequence checker and detach while holding lock.
456 ReleasableAutoLock releasable_auto_lock(&lock,
457 subtle::LockTracking::kEnabled);
458 SequenceCheckerImpl sequence_checker;
459 sequence_checker.DetachFromSequence();
460 releasable_auto_lock.Release();
461
462 // Re-bind without holding the lock.
463 EXPECT_TRUE(sequence_checker.CalledOnValidSequence());
464
465 ThreadPool::PostTask(BindLambdaForTesting([&] {
466 // Check sequencing while holding the lock. This is not valid because the
467 // sequence checker was detached and re-bound without the lock.
468 {
469 AutoLock auto_lock(lock, subtle::LockTracking::kEnabled);
470 EXPECT_FALSE(sequence_checker.CalledOnValidSequence());
471 }
472
473 thread_pool_done.Signal();
474 }));
475
476 thread_pool_done.Wait();
477 }
478
TEST(SequenceCheckerTest,LockMoveConstruction)479 TEST(SequenceCheckerTest, LockMoveConstruction) {
480 test::TaskEnvironment task_environment;
481 WaitableEvent thread_pool_done;
482 Lock lock;
483
484 // Create sequence checker and move-construct while holding a lock.
485 ReleasableAutoLock releasable_auto_lock(&lock,
486 subtle::LockTracking::kEnabled);
487 SequenceCheckerImpl sequence_checker;
488 SequenceCheckerImpl other_sequence_checker(std::move(sequence_checker));
489 releasable_auto_lock.Release();
490
491 ThreadPool::PostTask(BindLambdaForTesting([&] {
492 // Check sequencing while holding the lock.
493 {
494 AutoLock auto_lock(lock, subtle::LockTracking::kEnabled);
495 EXPECT_TRUE(other_sequence_checker.CalledOnValidSequence());
496 }
497
498 thread_pool_done.Signal();
499 }));
500
501 thread_pool_done.Wait();
502 }
503
TEST(SequenceCheckerTest,LockMoveAssignment)504 TEST(SequenceCheckerTest, LockMoveAssignment) {
505 test::TaskEnvironment task_environment;
506 WaitableEvent thread_pool_done;
507 Lock lock;
508
509 SequenceCheckerImpl other_sequence_checker;
510
511 // Create sequence checker and move-assign it to `other_sequence_checker`
512 // while holding a lock.
513 ReleasableAutoLock releasable_auto_lock(&lock,
514 subtle::LockTracking::kEnabled);
515 SequenceCheckerImpl sequence_checker;
516 other_sequence_checker = std::move(sequence_checker);
517 releasable_auto_lock.Release();
518
519 ThreadPool::PostTask(BindLambdaForTesting([&] {
520 // Check sequencing while holding the lock.
521 {
522 AutoLock auto_lock(lock, subtle::LockTracking::kEnabled);
523 EXPECT_TRUE(other_sequence_checker.CalledOnValidSequence());
524 }
525
526 thread_pool_done.Signal();
527 }));
528
529 thread_pool_done.Wait();
530 }
531 #endif // DCHECK_IS_ON()
532
533 } // namespace base::internal
534