• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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