123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285 |
- // Copyright 2013 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "base/sequence_checker.h"
- #include <stddef.h>
- #include <memory>
- #include <string>
- #include <utility>
- #include "base/bind.h"
- #include "base/callback_helpers.h"
- #include "base/sequence_token.h"
- #include "base/task/single_thread_task_runner.h"
- #include "base/task/thread_pool.h"
- #include "base/test/bind.h"
- #include "base/test/gtest_util.h"
- #include "base/test/task_environment.h"
- #include "base/threading/simple_thread.h"
- #include "base/threading/thread_local.h"
- #include "testing/gtest/include/gtest/gtest.h"
- namespace base {
- namespace {
- // Runs a callback on another thread.
- class RunCallbackThread : public SimpleThread {
- public:
- explicit RunCallbackThread(OnceClosure callback)
- : SimpleThread("RunCallbackThread"), callback_(std::move(callback)) {
- Start();
- Join();
- }
- RunCallbackThread(const RunCallbackThread&) = delete;
- RunCallbackThread& operator=(const RunCallbackThread&) = delete;
- private:
- // SimpleThread:
- void Run() override { std::move(callback_).Run(); }
- OnceClosure callback_;
- };
- void ExpectCalledOnValidSequence(SequenceCheckerImpl* sequence_checker) {
- ASSERT_TRUE(sequence_checker);
- // This should bind |sequence_checker| to the current sequence if it wasn't
- // already bound to a sequence.
- EXPECT_TRUE(sequence_checker->CalledOnValidSequence());
- // Since |sequence_checker| is now bound to the current sequence, another call
- // to CalledOnValidSequence() should return true.
- EXPECT_TRUE(sequence_checker->CalledOnValidSequence());
- }
- void ExpectCalledOnValidSequenceWithSequenceToken(
- SequenceCheckerImpl* sequence_checker,
- SequenceToken sequence_token) {
- ScopedSetSequenceTokenForCurrentThread
- scoped_set_sequence_token_for_current_thread(sequence_token);
- ExpectCalledOnValidSequence(sequence_checker);
- }
- void ExpectNotCalledOnValidSequence(SequenceCheckerImpl* sequence_checker) {
- ASSERT_TRUE(sequence_checker);
- EXPECT_FALSE(sequence_checker->CalledOnValidSequence());
- }
- } // namespace
- TEST(SequenceCheckerTest, CallsAllowedOnSameThreadNoSequenceToken) {
- SequenceCheckerImpl sequence_checker;
- EXPECT_TRUE(sequence_checker.CalledOnValidSequence());
- }
- TEST(SequenceCheckerTest, CallsAllowedOnSameThreadSameSequenceToken) {
- ScopedSetSequenceTokenForCurrentThread
- scoped_set_sequence_token_for_current_thread(SequenceToken::Create());
- SequenceCheckerImpl sequence_checker;
- EXPECT_TRUE(sequence_checker.CalledOnValidSequence());
- }
- TEST(SequenceCheckerTest, CallsDisallowedOnDifferentThreadsNoSequenceToken) {
- SequenceCheckerImpl sequence_checker;
- RunCallbackThread thread(
- BindOnce(&ExpectNotCalledOnValidSequence, Unretained(&sequence_checker)));
- }
- TEST(SequenceCheckerTest, CallsAllowedOnDifferentThreadsSameSequenceToken) {
- const SequenceToken sequence_token(SequenceToken::Create());
- ScopedSetSequenceTokenForCurrentThread
- scoped_set_sequence_token_for_current_thread(sequence_token);
- SequenceCheckerImpl sequence_checker;
- EXPECT_TRUE(sequence_checker.CalledOnValidSequence());
- RunCallbackThread thread(
- BindOnce(&ExpectCalledOnValidSequenceWithSequenceToken,
- Unretained(&sequence_checker), sequence_token));
- }
- TEST(SequenceCheckerTest, CallsDisallowedOnSameThreadDifferentSequenceToken) {
- std::unique_ptr<SequenceCheckerImpl> sequence_checker;
- {
- ScopedSetSequenceTokenForCurrentThread
- scoped_set_sequence_token_for_current_thread(SequenceToken::Create());
- sequence_checker = std::make_unique<SequenceCheckerImpl>();
- }
- {
- // Different SequenceToken.
- ScopedSetSequenceTokenForCurrentThread
- scoped_set_sequence_token_for_current_thread(SequenceToken::Create());
- EXPECT_FALSE(sequence_checker->CalledOnValidSequence());
- }
- // No SequenceToken.
- EXPECT_FALSE(sequence_checker->CalledOnValidSequence());
- }
- TEST(SequenceCheckerTest, DetachFromSequence) {
- std::unique_ptr<SequenceCheckerImpl> sequence_checker;
- {
- ScopedSetSequenceTokenForCurrentThread
- scoped_set_sequence_token_for_current_thread(SequenceToken::Create());
- sequence_checker = std::make_unique<SequenceCheckerImpl>();
- }
- sequence_checker->DetachFromSequence();
- {
- // Verify that CalledOnValidSequence() returns true when called with
- // a different sequence token after a call to DetachFromSequence().
- ScopedSetSequenceTokenForCurrentThread
- scoped_set_sequence_token_for_current_thread(SequenceToken::Create());
- EXPECT_TRUE(sequence_checker->CalledOnValidSequence());
- }
- }
- TEST(SequenceCheckerTest, DetachFromSequenceNoSequenceToken) {
- SequenceCheckerImpl sequence_checker;
- sequence_checker.DetachFromSequence();
- // Verify that CalledOnValidSequence() returns true when called on a
- // different thread after a call to DetachFromSequence().
- RunCallbackThread thread(
- BindOnce(&ExpectCalledOnValidSequence, Unretained(&sequence_checker)));
- EXPECT_FALSE(sequence_checker.CalledOnValidSequence());
- }
- TEST(SequenceCheckerTest, Move) {
- SequenceCheckerImpl initial;
- EXPECT_TRUE(initial.CalledOnValidSequence());
- SequenceCheckerImpl move_constructed(std::move(initial));
- EXPECT_TRUE(move_constructed.CalledOnValidSequence());
- SequenceCheckerImpl move_assigned;
- move_assigned = std::move(move_constructed);
- // The two SequenceCheckerImpls moved from should be able to rebind to another
- // sequence.
- RunCallbackThread thread1(
- BindOnce(&ExpectCalledOnValidSequence, Unretained(&initial)));
- RunCallbackThread thread2(
- BindOnce(&ExpectCalledOnValidSequence, Unretained(&move_constructed)));
- // But the latest one shouldn't be able to run on another sequence.
- RunCallbackThread thread(
- BindOnce(&ExpectNotCalledOnValidSequence, Unretained(&move_assigned)));
- EXPECT_TRUE(move_assigned.CalledOnValidSequence());
- }
- TEST(SequenceCheckerTest, MoveAssignIntoDetached) {
- SequenceCheckerImpl initial;
- SequenceCheckerImpl move_assigned;
- move_assigned.DetachFromSequence();
- move_assigned = std::move(initial);
- // |initial| is detached after move.
- RunCallbackThread thread1(
- BindOnce(&ExpectCalledOnValidSequence, Unretained(&initial)));
- // |move_assigned| should be associated with the main thread.
- RunCallbackThread thread2(
- BindOnce(&ExpectNotCalledOnValidSequence, Unretained(&move_assigned)));
- EXPECT_TRUE(move_assigned.CalledOnValidSequence());
- }
- TEST(SequenceCheckerTest, MoveFromDetachedRebinds) {
- SequenceCheckerImpl initial;
- initial.DetachFromSequence();
- SequenceCheckerImpl moved_into(std::move(initial));
- // |initial| is still detached after move.
- RunCallbackThread thread1(
- BindOnce(&ExpectCalledOnValidSequence, Unretained(&initial)));
- // |moved_into| is bound to the current sequence as part of the move.
- RunCallbackThread thread2(
- BindOnce(&ExpectNotCalledOnValidSequence, Unretained(&moved_into)));
- EXPECT_TRUE(moved_into.CalledOnValidSequence());
- }
- TEST(SequenceCheckerTest, MoveOffSequenceBanned) {
- testing::GTEST_FLAG(death_test_style) = "threadsafe";
- SequenceCheckerImpl other_sequence;
- other_sequence.DetachFromSequence();
- RunCallbackThread thread(
- BindOnce(&ExpectCalledOnValidSequence, Unretained(&other_sequence)));
- EXPECT_DCHECK_DEATH(
- SequenceCheckerImpl main_sequence(std::move(other_sequence)));
- }
- TEST(SequenceCheckerMacroTest, Macros) {
- auto scope = std::make_unique<ScopedSetSequenceTokenForCurrentThread>(
- SequenceToken::Create());
- SEQUENCE_CHECKER(my_sequence_checker);
- {
- // Don't expect a DCHECK death when a SequenceChecker is used on the right
- // sequence.
- DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker);
- }
- scope.reset();
- #if DCHECK_IS_ON()
- // Expect DCHECK death when used on a different sequence.
- EXPECT_DCHECK_DEATH(
- { DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker); });
- #else
- // Happily no-ops on non-dcheck builds.
- DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker);
- #endif
- DETACH_FROM_SEQUENCE(my_sequence_checker);
- // Don't expect a DCHECK death when a SequenceChecker is used for the first
- // time after having been detached.
- DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker);
- }
- // Owns a SequenceCheckerImpl, and asserts that CalledOnValidSequence() is valid
- // in ~SequenceCheckerOwner.
- class SequenceCheckerOwner {
- public:
- SequenceCheckerOwner() = default;
- SequenceCheckerOwner(const SequenceCheckerOwner&) = delete;
- SequenceCheckerOwner& operator=(const SequenceCheckerOwner&) = delete;
- ~SequenceCheckerOwner() { EXPECT_TRUE(checker_.CalledOnValidSequence()); }
- private:
- SequenceCheckerImpl checker_;
- };
- // Verifies SequenceCheckerImpl::CalledOnValidSequence() returns true if called
- // during thread destruction.
- TEST(SequenceCheckerTest, CalledOnValidSequenceFromThreadDestruction) {
- SequenceChecker::EnableStackLogging();
- ThreadLocalOwnedPointer<SequenceCheckerOwner> thread_local_owner;
- {
- test::TaskEnvironment task_environment;
- auto task_runner = ThreadPool::CreateSequencedTaskRunner({});
- task_runner->PostTask(
- FROM_HERE, BindLambdaForTesting([&]() {
- thread_local_owner.Set(std::make_unique<SequenceCheckerOwner>());
- }));
- task_runner = nullptr;
- task_environment.RunUntilIdle();
- }
- }
- } // namespace base
|