diff options
author | tommycli@chromium.org <tommycli@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-07-17 05:35:14 +0000 |
---|---|---|
committer | tommycli@chromium.org <tommycli@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-07-17 05:35:14 +0000 |
commit | 09a10057e09de243a53915d7ebeaad19c2f9e029 (patch) | |
tree | 5ad6b83e83b7aaec801fdc58621f65a685e54d3f | |
parent | a8c2847f56e56cc0470f807585dfc4a873902e9f (diff) | |
download | chromium_src-09a10057e09de243a53915d7ebeaad19c2f9e029.zip chromium_src-09a10057e09de243a53915d7ebeaad19c2f9e029.tar.gz chromium_src-09a10057e09de243a53915d7ebeaad19c2f9e029.tar.bz2 |
base: Change WeakPtr to use SequenceChecker instead of ThreadChecker.
This will enable WeakPtr to be used in SequencedWorkerPool, et al. with a sequence token.
This is a continuation of issue: https://chromiumcodereview.appspot.com/18231002/
The original issue got messed up by a rietveld bug, so refer there for history and comments.
BUG=165590
Review URL: https://chromiumcodereview.appspot.com/18501008
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@211956 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | base/base.gyp | 1 | ||||
-rw-r--r-- | base/memory/weak_ptr.cc | 12 | ||||
-rw-r--r-- | base/memory/weak_ptr.h | 6 | ||||
-rw-r--r-- | base/message_loop/message_pump_io_ios.h | 1 | ||||
-rw-r--r-- | base/sequence_checker.h | 16 | ||||
-rw-r--r-- | base/sequence_checker_impl.cc | 39 | ||||
-rw-r--r-- | base/sequence_checker_impl.h | 42 | ||||
-rw-r--r-- | base/sequence_checker_impl_unittest.cc | 218 | ||||
-rw-r--r-- | base/sequence_checker_unittest.cc | 328 | ||||
-rw-r--r-- | chrome/browser/storage_monitor/storage_monitor.h | 1 | ||||
-rw-r--r-- | content/renderer/media/webmediaplayer_ms.h | 1 | ||||
-rw-r--r-- | remoting/host/audio_capturer_win.h | 1 |
12 files changed, 374 insertions, 292 deletions
diff --git a/base/base.gyp b/base/base.gyp index 3e4f996..e4db68d 100644 --- a/base/base.gyp +++ b/base/base.gyp @@ -570,7 +570,6 @@ 'scoped_observer.h', 'security_unittest.cc', 'sequence_checker_unittest.cc', - 'sequence_checker_impl_unittest.cc', 'sha1_unittest.cc', 'stl_util_unittest.cc', 'strings/nullable_string16_unittest.cc', diff --git a/base/memory/weak_ptr.cc b/base/memory/weak_ptr.cc index a22f61a..d9ce86a 100644 --- a/base/memory/weak_ptr.cc +++ b/base/memory/weak_ptr.cc @@ -10,21 +10,21 @@ namespace internal { WeakReference::Flag::Flag() : is_valid_(true) { // Flags only become bound when checked for validity, or invalidated, // so that we can check that later validity/invalidation operations on - // the same Flag take place on the same thread. - thread_checker_.DetachFromThread(); + // the same Flag take place on the same sequenced thread. + sequence_checker_.DetachFromSequence(); } void WeakReference::Flag::Invalidate() { // The flag being invalidated with a single ref implies that there are no // weak pointers in existence. Allow deletion on other thread in this case. - DCHECK(thread_checker_.CalledOnValidThread() || HasOneRef()) - << "WeakPtrs must be checked and invalidated on the same thread."; + DCHECK(sequence_checker_.CalledOnValidSequencedThread() || HasOneRef()) + << "WeakPtrs must be invalidated on the same sequenced thread."; is_valid_ = false; } bool WeakReference::Flag::IsValid() const { - DCHECK(thread_checker_.CalledOnValidThread()) - << "WeakPtrs must be checked and invalidated on the same thread."; + DCHECK(sequence_checker_.CalledOnValidSequencedThread()) + << "WeakPtrs must be checked on the same sequenced thread."; return is_valid_; } diff --git a/base/memory/weak_ptr.h b/base/memory/weak_ptr.h index 621c0fa..b4120a1 100644 --- a/base/memory/weak_ptr.h +++ b/base/memory/weak_ptr.h @@ -67,8 +67,8 @@ #include "base/base_export.h" #include "base/logging.h" #include "base/memory/ref_counted.h" +#include "base/sequence_checker.h" #include "base/template_util.h" -#include "base/threading/thread_checker.h" namespace base { @@ -91,14 +91,14 @@ class BASE_EXPORT WeakReference { bool IsValid() const; // Remove this when crbug.com/234964 is addressed. - void DetachFromThreadHack() { thread_checker_.DetachFromThread(); } + void DetachFromThreadHack() { sequence_checker_.DetachFromSequence(); } private: friend class base::RefCountedThreadSafe<Flag>; ~Flag(); - ThreadChecker thread_checker_; + SequenceChecker sequence_checker_; bool is_valid_; }; diff --git a/base/message_loop/message_pump_io_ios.h b/base/message_loop/message_pump_io_ios.h index 6596862b..6779aab 100644 --- a/base/message_loop/message_pump_io_ios.h +++ b/base/message_loop/message_pump_io_ios.h @@ -11,6 +11,7 @@ #include "base/memory/ref_counted.h" #include "base/message_loop/message_pump_mac.h" #include "base/observer_list.h" +#include "base/threading/thread_checker.h" namespace base { diff --git a/base/sequence_checker.h b/base/sequence_checker.h index fbf146a..89bbd7e 100644 --- a/base/sequence_checker.h +++ b/base/sequence_checker.h @@ -28,12 +28,11 @@ class SequencedTaskRunner; // the right version for your build configuration. class SequenceCheckerDoNothing { public: - bool CalledOnValidSequence() const { + bool CalledOnValidSequencedThread() const { return true; } - void ChangeSequence( - const scoped_refptr<SequencedTaskRunner>& sequenced_task_runner) {} + void DetachFromSequence() {} }; // SequenceChecker is a helper class used to help verify that some @@ -44,10 +43,6 @@ class SequenceCheckerDoNothing { // Example: // class MyClass { // public: -// explicit MyClass( -// const scoped_refptr<SequencedTaskRunner>& sequenced_task_runner) -// : sequence_checker_(sequenced_task_runner) {} -// // void Foo() { // DCHECK(sequence_checker_.CalledOnValidSequence()); // ... (do stuff) ... @@ -60,16 +55,9 @@ class SequenceCheckerDoNothing { // In Release mode, CalledOnValidSequence will always return true. #if ENABLE_SEQUENCE_CHECKER class SequenceChecker : public SequenceCheckerImpl { - public: - explicit SequenceChecker( - const scoped_refptr<SequencedTaskRunner>& sequenced_task_runner) - : SequenceCheckerImpl(sequenced_task_runner) {} }; #else class SequenceChecker : public SequenceCheckerDoNothing { - public: - explicit SequenceChecker( - const scoped_refptr<SequencedTaskRunner>& sequenced_task_runner) {} }; #endif // ENABLE_SEQUENCE_CHECKER diff --git a/base/sequence_checker_impl.cc b/base/sequence_checker_impl.cc index 24d9ed9..e95b8ee 100644 --- a/base/sequence_checker_impl.cc +++ b/base/sequence_checker_impl.cc @@ -4,28 +4,43 @@ #include "base/sequence_checker_impl.h" -#include "base/sequenced_task_runner.h" - namespace base { -SequenceCheckerImpl::SequenceCheckerImpl( - const scoped_refptr<SequencedTaskRunner>& sequenced_task_runner) - : sequenced_task_runner_(sequenced_task_runner) {} +SequenceCheckerImpl::SequenceCheckerImpl() + : sequence_token_assigned_(false) { + AutoLock auto_lock(lock_); + EnsureSequenceTokenAssigned(); +} SequenceCheckerImpl::~SequenceCheckerImpl() {} -bool SequenceCheckerImpl::CalledOnValidSequence() const { +bool SequenceCheckerImpl::CalledOnValidSequencedThread() const { AutoLock auto_lock(lock_); - return sequenced_task_runner_.get() ? - sequenced_task_runner_->RunsTasksOnCurrentThread() : - thread_checker_.CalledOnValidThread(); + EnsureSequenceTokenAssigned(); + + // If this thread is not associated with a SequencedWorkerPool, + // SequenceChecker behaves as a ThreadChecker. See header for details. + if (!sequence_token_.IsValid()) + return thread_checker_.CalledOnValidThread(); + + return sequence_token_.Equals( + SequencedWorkerPool::GetSequenceTokenForCurrentThread()); } -void SequenceCheckerImpl::ChangeSequence( - const scoped_refptr<SequencedTaskRunner>& sequenced_task_runner) { +void SequenceCheckerImpl::DetachFromSequence() { AutoLock auto_lock(lock_); - sequenced_task_runner_ = sequenced_task_runner; thread_checker_.DetachFromThread(); + sequence_token_assigned_ = false; + sequence_token_ = SequencedWorkerPool::SequenceToken(); +} + +void SequenceCheckerImpl::EnsureSequenceTokenAssigned() const { + lock_.AssertAcquired(); + if (sequence_token_assigned_) + return; + + sequence_token_assigned_ = true; + sequence_token_ = SequencedWorkerPool::GetSequenceTokenForCurrentThread(); } } // namespace base diff --git a/base/sequence_checker_impl.h b/base/sequence_checker_impl.h index ccd1198..741aafe 100644 --- a/base/sequence_checker_impl.h +++ b/base/sequence_checker_impl.h @@ -7,48 +7,42 @@ #include "base/base_export.h" #include "base/basictypes.h" -#include "base/memory/ref_counted.h" #include "base/synchronization/lock.h" +#include "base/threading/sequenced_worker_pool.h" #include "base/threading/thread_checker_impl.h" namespace base { -class SequencedTaskRunner; - // SequenceCheckerImpl is used to help verify that some methods of a // class are called in sequence -- that is, called from the same // SequencedTaskRunner. It is a generalization of ThreadChecker; in -// particular, it behaves exactly like ThreadChecker if its passed a -// NULL SequencedTaskRunner. +// particular, it behaves exactly like ThreadChecker if constructed +// on a thread that is not part of a SequencedWorkerPool. class BASE_EXPORT SequenceCheckerImpl { public: - // |sequenced_task_runner| can be NULL. In that case, this object - // behaves exactly like a ThreadChecker bound to the current thread, - // i.e. CalledOnValidSequence() behaves like CalledOnValidThread(). - explicit SequenceCheckerImpl( - const scoped_refptr<SequencedTaskRunner>& sequenced_task_runner); + SequenceCheckerImpl(); ~SequenceCheckerImpl(); - // Returns whether the we are being called on the underyling - // SequencedTaskRunner. If we're not bound to a - // |sequenced_task_runner|, returns whether we are being called on - // the underlying ThreadChecker's thread. - bool CalledOnValidSequence() const; + // Returns whether the we are being called on the same sequence token + // as previous calls. If there is no associated sequence, then returns + // whether we are being called on the underlying ThreadChecker's thread. + bool CalledOnValidSequencedThread() const; - // Changes the underyling SequencedTaskRunner. - // |sequenced_task_runner| can be NULL. In that case, this object - // behaves exactly like a ThreadChecker that has been detached from - // its thread, i.e. we will be bound to the thread on which we next - // call CalledOnValidSequence(). - void ChangeSequence( - const scoped_refptr<SequencedTaskRunner>& sequenced_task_runner); + // Unbinds the checker from the currently associated sequence. The + // checker will be re-bound on the next call to CalledOnValidSequence(). + void DetachFromSequence(); private: + void EnsureSequenceTokenAssigned() const; + // Guards all variables below. mutable Lock lock_; - scoped_refptr<SequencedTaskRunner> sequenced_task_runner_; - // Used if |sequenced_task_runner_| is NULL. + + // Used if |sequence_token_| is not valid. ThreadCheckerImpl thread_checker_; + mutable bool sequence_token_assigned_; + + mutable SequencedWorkerPool::SequenceToken sequence_token_; DISALLOW_COPY_AND_ASSIGN(SequenceCheckerImpl); }; diff --git a/base/sequence_checker_impl_unittest.cc b/base/sequence_checker_impl_unittest.cc deleted file mode 100644 index 4e601b0..0000000 --- a/base/sequence_checker_impl_unittest.cc +++ /dev/null @@ -1,218 +0,0 @@ -// Copyright (c) 2012 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_impl.h" - -#include <cstddef> - -#include "base/bind.h" -#include "base/compiler_specific.h" -#include "base/location.h" -#include "base/memory/ref_counted.h" -#include "base/message_loop.h" -#include "base/sequenced_task_runner.h" -#include "base/threading/thread.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -namespace { - -// Implementation of SequencedTaskRunner that lets us control what -// RunsTasksOnCurrentThread() returns. -class FakeTaskRunner : public SequencedTaskRunner { - public: - FakeTaskRunner() : runs_tasks_on_current_thread_(false) {} - - void SetRunsTasksOnCurrentThread(bool runs_tasks_on_current_thread) { - runs_tasks_on_current_thread_ = runs_tasks_on_current_thread; - } - - // SequencedTaskRunner implementation. - virtual bool PostDelayedTask(const tracked_objects::Location& from_here, - const Closure& task, - TimeDelta delay) OVERRIDE { - ADD_FAILURE(); - return false; - } - - virtual bool PostNonNestableDelayedTask( - const tracked_objects::Location& from_here, - const Closure& task, - TimeDelta delay) OVERRIDE { - ADD_FAILURE(); - return false; - } - - virtual bool RunsTasksOnCurrentThread() const OVERRIDE { - return runs_tasks_on_current_thread_; - } - - protected: - virtual ~FakeTaskRunner() {} - - private: - bool runs_tasks_on_current_thread_; -}; - -class SequenceCheckerImplTest : public ::testing::Test { -}; - -// Create a SequenceCheckerImpl with a SequencedTaskRunner and make -// sure that CalledOnValidSequence() returns what that SequencedTaskRunner -// returns for RunsTasksOnCurrentThread(). -TEST_F(SequenceCheckerImplTest, CalledOnValidSequenceNonNull) { - const scoped_refptr<FakeTaskRunner> fake_sequenced_task_runner( - new FakeTaskRunner()); - - const SequenceCheckerImpl sequence_checker_impl(fake_sequenced_task_runner); - EXPECT_FALSE(sequence_checker_impl.CalledOnValidSequence()); - - fake_sequenced_task_runner->SetRunsTasksOnCurrentThread(true); - EXPECT_TRUE(sequence_checker_impl.CalledOnValidSequence()); - - fake_sequenced_task_runner->SetRunsTasksOnCurrentThread(false); - EXPECT_FALSE(sequence_checker_impl.CalledOnValidSequence()); -} - -void ExpectCalledOnValidSequence( - const tracked_objects::Location& location, - const SequenceCheckerImpl* sequence_checker_impl, - bool expected_value) { - EXPECT_EQ(expected_value, sequence_checker_impl->CalledOnValidSequence()) - << location.ToString(); -} - -// Create a SequenceCheckerImpl with no SequencedTaskRunner and make -// sure that CalledOnValidSequence() behaves like -// ThreadChecker::CalledOnValidThread(). -TEST_F(SequenceCheckerImplTest, CalledOnValidSequenceNull) { - const SequenceCheckerImpl sequence_checker_impl(NULL); - EXPECT_TRUE(sequence_checker_impl.CalledOnValidSequence()); - - { - Thread thread("thread 1"); - ASSERT_TRUE(thread.Start()); - thread.message_loop()->PostTask( - FROM_HERE, Bind(&ExpectCalledOnValidSequence, - FROM_HERE, - Unretained(&sequence_checker_impl), - false)); - } - - EXPECT_TRUE(sequence_checker_impl.CalledOnValidSequence()); -} - -// Create a SequenceCheckerImpl with a SequencedTaskRunner and switch -// it to another one. CalledOnValidSequence() should return what its -// underlying SequencedTaskRunner returns for -// RunsTasksOnCurrentThread(). -TEST_F(SequenceCheckerImplTest, ChangeSequenceNonNull) { - const scoped_refptr<FakeTaskRunner> fake_sequenced_task_runner1( - new FakeTaskRunner()); - - const scoped_refptr<FakeTaskRunner> fake_sequenced_task_runner2( - new FakeTaskRunner()); - - SequenceCheckerImpl sequence_checker_impl(fake_sequenced_task_runner1); - EXPECT_FALSE(sequence_checker_impl.CalledOnValidSequence()); - - fake_sequenced_task_runner2->SetRunsTasksOnCurrentThread(true); - EXPECT_FALSE(sequence_checker_impl.CalledOnValidSequence()); - - sequence_checker_impl.ChangeSequence(fake_sequenced_task_runner2); - EXPECT_TRUE(sequence_checker_impl.CalledOnValidSequence()); - - sequence_checker_impl.ChangeSequence(fake_sequenced_task_runner1); - EXPECT_FALSE(sequence_checker_impl.CalledOnValidSequence()); -} - -// Create a SequenceCheckerImpl with a SequencedTaskRunner and switch -// it to a NULL one. CalledOnValidSequence() should then behave like -// ThreadChecker::CalledOnValidThread(). -TEST_F(SequenceCheckerImplTest, ChangeSequenceNull) { - const scoped_refptr<FakeTaskRunner> fake_sequenced_task_runner( - new FakeTaskRunner()); - - SequenceCheckerImpl sequence_checker_impl(fake_sequenced_task_runner); - EXPECT_FALSE(sequence_checker_impl.CalledOnValidSequence()); - - sequence_checker_impl.ChangeSequence(NULL); - // Binds to current thread. - EXPECT_TRUE(sequence_checker_impl.CalledOnValidSequence()); - { - Thread thread("thread 1"); - ASSERT_TRUE(thread.Start()); - thread.message_loop()->PostTask( - FROM_HERE, Bind(&ExpectCalledOnValidSequence, - FROM_HERE, - Unretained(&sequence_checker_impl), - false)); - } - - EXPECT_TRUE(sequence_checker_impl.CalledOnValidSequence()); - - sequence_checker_impl.ChangeSequence(NULL); - // Binds to worker thread. - { - Thread thread("thread 2"); - ASSERT_TRUE(thread.Start()); - thread.message_loop()->PostTask( - FROM_HERE, Bind(&ExpectCalledOnValidSequence, - FROM_HERE, - Unretained(&sequence_checker_impl), - true)); - } - EXPECT_FALSE(sequence_checker_impl.CalledOnValidSequence()); -} - -// Create a SequenceCheckerImpl with the current thread's task runner -// and switch it to other task runners. CalledOnValidSequence() should -// return true only when it's on the correct thread. -TEST_F(SequenceCheckerImplTest, MultipleThreads) { - MessageLoop loop; - - SequenceCheckerImpl sequence_checker_impl(loop.message_loop_proxy()); - EXPECT_TRUE(sequence_checker_impl.CalledOnValidSequence()); - - { - Thread thread("thread 1"); - ASSERT_TRUE(thread.Start()); - thread.message_loop()->PostTask( - FROM_HERE, Bind(&ExpectCalledOnValidSequence, - FROM_HERE, - Unretained(&sequence_checker_impl), - false)); - thread.message_loop()->PostTask( - FROM_HERE, Bind(&SequenceCheckerImpl::ChangeSequence, - Unretained(&sequence_checker_impl), - thread.message_loop_proxy())); - thread.message_loop()->PostTask( - FROM_HERE, Bind(&ExpectCalledOnValidSequence, - FROM_HERE, - Unretained(&sequence_checker_impl), - true)); - } - - EXPECT_FALSE(sequence_checker_impl.CalledOnValidSequence()); - - sequence_checker_impl.ChangeSequence(loop.message_loop_proxy()); - EXPECT_TRUE(sequence_checker_impl.CalledOnValidSequence()); - - { - Thread thread("thread 2"); - ASSERT_TRUE(thread.Start()); - thread.message_loop()->PostTask( - FROM_HERE, Bind(&ExpectCalledOnValidSequence, - FROM_HERE, - Unretained(&sequence_checker_impl), - false)); - } - - EXPECT_TRUE(sequence_checker_impl.CalledOnValidSequence()); -} - -} // namespace - -} // namespace base diff --git a/base/sequence_checker_unittest.cc b/base/sequence_checker_unittest.cc index 4fc3027..e093fa8 100644 --- a/base/sequence_checker_unittest.cc +++ b/base/sequence_checker_unittest.cc @@ -1,29 +1,329 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// 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 <cstddef> - -#include "base/compiler_specific.h" +#include "base/basictypes.h" +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/location.h" +#include "base/logging.h" #include "base/memory/ref_counted.h" -#include "base/test/null_task_runner.h" +#include "base/memory/scoped_ptr.h" +#include "base/message_loop.h" +#include "base/sequence_checker.h" +#include "base/test/sequenced_worker_pool_owner.h" +#include "base/threading/thread.h" #include "testing/gtest/include/gtest/gtest.h" +// Duplicated from base/sequence_checker.h so that we can be good citizens +// there and undef the macro. +#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) +#define ENABLE_SEQUENCE_CHECKER 1 +#else +#define ENABLE_SEQUENCE_CHECKER 0 +#endif + namespace base { namespace { -// Call various methods of SequenceChecker to make sure nothing blows -// up in either debug or release mode. -TEST(SequenceCheckerTest, Basic) { - SequenceChecker sequence_checker(new NullTaskRunner()); - sequence_checker.CalledOnValidSequence(); - sequence_checker.ChangeSequence(NULL); - sequence_checker.CalledOnValidSequence(); +const size_t kNumWorkerThreads = 3; + +// Simple class to exercise the basics of SequenceChecker. +// DoStuff should verify that it's called on a valid sequenced thread. +// SequenceCheckedObject can be destroyed on any thread (like WeakPtr). +class SequenceCheckedObject { + public: + SequenceCheckedObject() {} + ~SequenceCheckedObject() {} + + // Verifies that it was called on the same thread as the constructor. + void DoStuff() { + DCHECK(sequence_checker_.CalledOnValidSequencedThread()); + } + + void DetachFromSequence() { + sequence_checker_.DetachFromSequence(); + } + + private: + SequenceChecker sequence_checker_; + + DISALLOW_COPY_AND_ASSIGN(SequenceCheckedObject); +}; + +class SequenceCheckerTest : public testing::Test { + public: + SequenceCheckerTest() : other_thread_("sequence_checker_test_other_thread") {} + + virtual ~SequenceCheckerTest() {} + + virtual void SetUp() OVERRIDE { + other_thread_.Start(); + ResetPool(); + } + + virtual void TearDown() OVERRIDE { + other_thread_.Stop(); + pool()->Shutdown(); + } + + protected: + base::Thread* other_thread() { return &other_thread_; } + + const scoped_refptr<SequencedWorkerPool>& pool() { + return pool_owner_->pool(); + } + + void PostDoStuffToWorkerPool(SequenceCheckedObject* sequence_checked_object, + const std::string& token_name) { + pool()->PostNamedSequencedWorkerTask( + token_name, + FROM_HERE, + base::Bind(&SequenceCheckedObject::DoStuff, + base::Unretained(sequence_checked_object))); + } + + void PostDoStuffToOtherThread( + SequenceCheckedObject* sequence_checked_object) { + other_thread()->message_loop()->PostTask( + FROM_HERE, + base::Bind(&SequenceCheckedObject::DoStuff, + base::Unretained(sequence_checked_object))); + } + + void PostDeleteToOtherThread( + scoped_ptr<SequenceCheckedObject> sequence_checked_object) { + other_thread()->message_loop()->DeleteSoon( + FROM_HERE, + sequence_checked_object.release()); + } + + // Destroys the SequencedWorkerPool instance, blocking until it is fully shut + // down, and creates a new instance. + void ResetPool() { + pool_owner_.reset(new SequencedWorkerPoolOwner(kNumWorkerThreads, "test")); + } + + void MethodOnDifferentThreadDeathTest(); + void DetachThenCallFromDifferentThreadDeathTest(); + void DifferentSequenceTokensDeathTest(); + void WorkerPoolAndSimpleThreadDeathTest(); + void TwoDifferentWorkerPoolsDeathTest(); + + private: + MessageLoop message_loop_; // Needed by SequencedWorkerPool to function. + base::Thread other_thread_; + scoped_ptr<SequencedWorkerPoolOwner> pool_owner_; +}; + +TEST_F(SequenceCheckerTest, CallsAllowedOnSameThread) { + scoped_ptr<SequenceCheckedObject> sequence_checked_object( + new SequenceCheckedObject); + + // Verify that DoStuff doesn't assert. + sequence_checked_object->DoStuff(); + + // Verify that the destructor doesn't assert. + sequence_checked_object.reset(); +} + +TEST_F(SequenceCheckerTest, DestructorAllowedOnDifferentThread) { + scoped_ptr<SequenceCheckedObject> sequence_checked_object( + new SequenceCheckedObject); + + // Verify the destructor doesn't assert when called on a different thread. + PostDeleteToOtherThread(sequence_checked_object.Pass()); + other_thread()->Stop(); +} + +TEST_F(SequenceCheckerTest, DetachFromSequence) { + scoped_ptr<SequenceCheckedObject> sequence_checked_object( + new SequenceCheckedObject); + + // Verify that DoStuff doesn't assert when called on a different thread after + // a call to DetachFromSequence. + sequence_checked_object->DetachFromSequence(); + + PostDoStuffToOtherThread(sequence_checked_object.get()); + other_thread()->Stop(); +} + +TEST_F(SequenceCheckerTest, SameSequenceTokenValid) { + scoped_ptr<SequenceCheckedObject> sequence_checked_object( + new SequenceCheckedObject); + + sequence_checked_object->DetachFromSequence(); + PostDoStuffToWorkerPool(sequence_checked_object.get(), "A"); + PostDoStuffToWorkerPool(sequence_checked_object.get(), "A"); + PostDoStuffToWorkerPool(sequence_checked_object.get(), "A"); + PostDoStuffToWorkerPool(sequence_checked_object.get(), "A"); + pool()->FlushForTesting(); + + PostDeleteToOtherThread(sequence_checked_object.Pass()); + other_thread()->Stop(); +} + +TEST_F(SequenceCheckerTest, DetachSequenceTokenValid) { + scoped_ptr<SequenceCheckedObject> sequence_checked_object( + new SequenceCheckedObject); + + sequence_checked_object->DetachFromSequence(); + PostDoStuffToWorkerPool(sequence_checked_object.get(), "A"); + PostDoStuffToWorkerPool(sequence_checked_object.get(), "A"); + pool()->FlushForTesting(); + + sequence_checked_object->DetachFromSequence(); + PostDoStuffToWorkerPool(sequence_checked_object.get(), "B"); + PostDoStuffToWorkerPool(sequence_checked_object.get(), "B"); + pool()->FlushForTesting(); + + PostDeleteToOtherThread(sequence_checked_object.Pass()); + other_thread()->Stop(); +} + +#if GTEST_HAS_DEATH_TEST || !ENABLE_SEQUENCE_CHECKER + +void SequenceCheckerTest::MethodOnDifferentThreadDeathTest() { + scoped_ptr<SequenceCheckedObject> sequence_checked_object( + new SequenceCheckedObject); + + // DoStuff should assert in debug builds only when called on a + // different thread. + PostDoStuffToOtherThread(sequence_checked_object.get()); + other_thread()->Stop(); +} + +#if ENABLE_SEQUENCE_CHECKER +TEST_F(SequenceCheckerTest, MethodNotAllowedOnDifferentThreadDeathTestInDebug) { + ASSERT_DEATH({ + MethodOnDifferentThreadDeathTest(); + }, ""); +} +#else +TEST_F(SequenceCheckerTest, MethodAllowedOnDifferentThreadDeathTestInRelease) { + MethodOnDifferentThreadDeathTest(); +} +#endif // ENABLE_SEQUENCE_CHECKER + +void SequenceCheckerTest::DetachThenCallFromDifferentThreadDeathTest() { + scoped_ptr<SequenceCheckedObject> sequence_checked_object( + new SequenceCheckedObject); + + // DoStuff doesn't assert when called on a different thread + // after a call to DetachFromSequence. + sequence_checked_object->DetachFromSequence(); + PostDoStuffToOtherThread(sequence_checked_object.get()); + other_thread()->Stop(); + + // DoStuff should assert in debug builds only after moving to + // another thread. + sequence_checked_object->DoStuff(); +} + +#if ENABLE_SEQUENCE_CHECKER +TEST_F(SequenceCheckerTest, DetachFromSequenceDeathTestInDebug) { + ASSERT_DEATH({ + DetachThenCallFromDifferentThreadDeathTest(); + }, ""); +} +#else +TEST_F(SequenceCheckerTest, DetachFromThreadDeathTestInRelease) { + DetachThenCallFromDifferentThreadDeathTest(); +} +#endif // ENABLE_SEQUENCE_CHECKER + +void SequenceCheckerTest::DifferentSequenceTokensDeathTest() { + scoped_ptr<SequenceCheckedObject> sequence_checked_object( + new SequenceCheckedObject); + + sequence_checked_object->DetachFromSequence(); + PostDoStuffToWorkerPool(sequence_checked_object.get(), "A"); + PostDoStuffToWorkerPool(sequence_checked_object.get(), "A"); + PostDoStuffToWorkerPool(sequence_checked_object.get(), "B"); + PostDoStuffToWorkerPool(sequence_checked_object.get(), "B"); + pool()->FlushForTesting(); + + PostDeleteToOtherThread(sequence_checked_object.Pass()); + other_thread()->Stop(); } +#if ENABLE_SEQUENCE_CHECKER +TEST_F(SequenceCheckerTest, DifferentSequenceTokensDeathTestInDebug) { + ASSERT_DEATH({ + DifferentSequenceTokensDeathTest(); + }, ""); +} +#else +TEST_F(SequenceCheckerTest, + DifferentSequenceTokensDeathTestInRelease) { + DifferentSequenceTokensDeathTest(); +} +#endif // ENABLE_SEQUENCE_CHECKER + +void SequenceCheckerTest::WorkerPoolAndSimpleThreadDeathTest() { + scoped_ptr<SequenceCheckedObject> sequence_checked_object( + new SequenceCheckedObject); + + sequence_checked_object->DetachFromSequence(); + PostDoStuffToWorkerPool(sequence_checked_object.get(), "A"); + PostDoStuffToWorkerPool(sequence_checked_object.get(), "A"); + pool()->FlushForTesting(); + + PostDoStuffToOtherThread(sequence_checked_object.get()); + other_thread()->Stop(); +} + +#if ENABLE_SEQUENCE_CHECKER +TEST_F(SequenceCheckerTest, WorkerPoolAndSimpleThreadDeathTestInDebug) { + ASSERT_DEATH({ + WorkerPoolAndSimpleThreadDeathTest(); + }, ""); +} +#else +TEST_F(SequenceCheckerTest, + WorkerPoolAndSimpleThreadDeathTestInRelease) { + WorkerPoolAndSimpleThreadDeathTest(); +} +#endif // ENABLE_SEQUENCE_CHECKER + +void SequenceCheckerTest::TwoDifferentWorkerPoolsDeathTest() { + scoped_ptr<SequenceCheckedObject> sequence_checked_object( + new SequenceCheckedObject); + + sequence_checked_object->DetachFromSequence(); + PostDoStuffToWorkerPool(sequence_checked_object.get(), "A"); + PostDoStuffToWorkerPool(sequence_checked_object.get(), "A"); + pool()->FlushForTesting(); + + SequencedWorkerPoolOwner second_pool_owner(kNumWorkerThreads, "test2"); + second_pool_owner.pool()->PostNamedSequencedWorkerTask( + "A", + FROM_HERE, + base::Bind(&SequenceCheckedObject::DoStuff, + base::Unretained(sequence_checked_object.get()))); + second_pool_owner.pool()->FlushForTesting(); + second_pool_owner.pool()->Shutdown(); +} + +#if ENABLE_SEQUENCE_CHECKER +TEST_F(SequenceCheckerTest, TwoDifferentWorkerPoolsDeathTestInDebug) { + ASSERT_DEATH({ + TwoDifferentWorkerPoolsDeathTest(); + }, ""); +} +#else +TEST_F(SequenceCheckerTest, + TwoDifferentWorkerPoolsDeathTestInRelease) { + TwoDifferentWorkerPoolsDeathTest(); +} +#endif // ENABLE_SEQUENCE_CHECKER + +#endif // GTEST_HAS_DEATH_TEST || !ENABLE_SEQUENCE_CHECKER + } // namespace } // namespace base + +// Just in case we ever get lumped together with other compilation units. +#undef ENABLE_SEQUENCE_CHECKER diff --git a/chrome/browser/storage_monitor/storage_monitor.h b/chrome/browser/storage_monitor/storage_monitor.h index 36e81e9..9258dd4 100644 --- a/chrome/browser/storage_monitor/storage_monitor.h +++ b/chrome/browser/storage_monitor/storage_monitor.h @@ -14,6 +14,7 @@ #include "base/observer_list_threadsafe.h" #include "base/strings/string16.h" #include "base/synchronization/lock.h" +#include "base/threading/thread_checker.h" #include "chrome/browser/storage_monitor/storage_info.h" class ChromeBrowserMainPartsLinux; diff --git a/content/renderer/media/webmediaplayer_ms.h b/content/renderer/media/webmediaplayer_ms.h index 106e0bc..fae271b 100644 --- a/content/renderer/media/webmediaplayer_ms.h +++ b/content/renderer/media/webmediaplayer_ms.h @@ -9,6 +9,7 @@ #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "base/synchronization/lock.h" +#include "base/threading/thread_checker.h" #include "cc/layers/video_frame_provider.h" #include "media/filters/skcanvas_video_renderer.h" #include "skia/ext/platform_canvas.h" diff --git a/remoting/host/audio_capturer_win.h b/remoting/host/audio_capturer_win.h index c871bca..1a7ddad 100644 --- a/remoting/host/audio_capturer_win.h +++ b/remoting/host/audio_capturer_win.h @@ -10,6 +10,7 @@ #include "base/basictypes.h" #include "base/memory/scoped_ptr.h" +#include "base/threading/thread_checker.h" #include "base/timer/timer.h" #include "base/win/scoped_co_mem.h" #include "base/win/scoped_comptr.h" |