summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
authorakalin@chromium.org <akalin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-12-27 19:58:00 +0000
committerakalin@chromium.org <akalin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-12-27 19:58:00 +0000
commit399ed423f1c7f84190a7030496ac76e9eaf945f6 (patch)
tree651cc32e6b10cdb5800e5ffd9cb01f4280acac4b /base
parent5f061c2ccd015d5c62b0d95021383e53b47e04c5 (diff)
downloadchromium_src-399ed423f1c7f84190a7030496ac76e9eaf945f6.zip
chromium_src-399ed423f1c7f84190a7030496ac76e9eaf945f6.tar.gz
chromium_src-399ed423f1c7f84190a7030496ac76e9eaf945f6.tar.bz2
Implement SequenceChecker, which is a generalization of ThreadChecker
SequenceChecker will be used in WeakPtr instead of ThreadChecker, since WeakPtr needs only the guarantees of a SequencedTaskRunner. Add NullTaskRunner implementation and make test_browser_context.cc use it. BUG=165590 Review URL: https://codereview.chromium.org/11550031 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@174693 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base')
-rw-r--r--base/base.gyp4
-rw-r--r--base/base.gypi3
-rw-r--r--base/sequence_checker.h80
-rw-r--r--base/sequence_checker_impl.cc31
-rw-r--r--base/sequence_checker_impl.h58
-rw-r--r--base/sequence_checker_impl_unittest.cc218
-rw-r--r--base/sequence_checker_unittest.cc29
-rw-r--r--base/test/null_task_runner.cc31
-rw-r--r--base/test/null_task_runner.h34
9 files changed, 488 insertions, 0 deletions
diff --git a/base/base.gyp b/base/base.gyp
index 51122c4..a584ae4 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -512,6 +512,8 @@
'rand_util_unittest.cc',
'scoped_native_library_unittest.cc',
'scoped_observer.h',
+ 'sequence_checker_unittest.cc',
+ 'sequence_checker_impl_unittest.cc',
'sha1_unittest.cc',
'shared_memory_unittest.cc',
'stl_util_unittest.cc',
@@ -784,6 +786,8 @@
'test/multiprocess_test.cc',
'test/multiprocess_test.h',
'test/multiprocess_test_android.cc',
+ 'test/null_task_runner.cc',
+ 'test/null_task_runner.h',
'test/perf_test_suite.cc',
'test/perf_test_suite.h',
'test/scoped_locale.cc',
diff --git a/base/base.gypi b/base/base.gypi
index 6ea3a07..99e16ab 100644
--- a/base/base.gypi
+++ b/base/base.gypi
@@ -353,6 +353,9 @@
'safe_strerror_posix.h',
'scoped_native_library.cc',
'scoped_native_library.h',
+ 'sequence_checker.h',
+ 'sequence_checker_impl.cc',
+ 'sequence_checker_impl.h',
'sequenced_task_runner.cc',
'sequenced_task_runner.h',
'sequenced_task_runner_helpers.h',
diff --git a/base/sequence_checker.h b/base/sequence_checker.h
new file mode 100644
index 0000000..fbf146a
--- /dev/null
+++ b/base/sequence_checker.h
@@ -0,0 +1,80 @@
+// 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.
+
+#ifndef BASE_SEQUENCE_CHECKER_H_
+#define BASE_SEQUENCE_CHECKER_H_
+
+#include "base/memory/ref_counted.h"
+
+// See comments for the similar block in thread_checker.h.
+#if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON))
+#define ENABLE_SEQUENCE_CHECKER 1
+#else
+#define ENABLE_SEQUENCE_CHECKER 0
+#endif
+
+#if ENABLE_SEQUENCE_CHECKER
+#include "base/sequence_checker_impl.h"
+#endif
+
+namespace base {
+
+class SequencedTaskRunner;
+
+// Do nothing implementation, for use in release mode.
+//
+// Note: You should almost always use the SequenceChecker class to get
+// the right version for your build configuration.
+class SequenceCheckerDoNothing {
+ public:
+ bool CalledOnValidSequence() const {
+ return true;
+ }
+
+ void ChangeSequence(
+ const scoped_refptr<SequencedTaskRunner>& sequenced_task_runner) {}
+};
+
+// SequenceChecker is a helper class 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; see comments in sequence_checker_impl.h for details.
+//
+// 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) ...
+// }
+//
+// private:
+// SequenceChecker sequence_checker_;
+// }
+//
+// 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
+
+#undef ENABLE_SEQUENCE_CHECKER
+
+} // namespace base
+
+#endif // BASE_SEQUENCE_CHECKER_H_
diff --git a/base/sequence_checker_impl.cc b/base/sequence_checker_impl.cc
new file mode 100644
index 0000000..24d9ed9
--- /dev/null
+++ b/base/sequence_checker_impl.cc
@@ -0,0 +1,31 @@
+// 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 "base/sequenced_task_runner.h"
+
+namespace base {
+
+SequenceCheckerImpl::SequenceCheckerImpl(
+ const scoped_refptr<SequencedTaskRunner>& sequenced_task_runner)
+ : sequenced_task_runner_(sequenced_task_runner) {}
+
+SequenceCheckerImpl::~SequenceCheckerImpl() {}
+
+bool SequenceCheckerImpl::CalledOnValidSequence() const {
+ AutoLock auto_lock(lock_);
+ return sequenced_task_runner_.get() ?
+ sequenced_task_runner_->RunsTasksOnCurrentThread() :
+ thread_checker_.CalledOnValidThread();
+}
+
+void SequenceCheckerImpl::ChangeSequence(
+ const scoped_refptr<SequencedTaskRunner>& sequenced_task_runner) {
+ AutoLock auto_lock(lock_);
+ sequenced_task_runner_ = sequenced_task_runner;
+ thread_checker_.DetachFromThread();
+}
+
+} // namespace base
diff --git a/base/sequence_checker_impl.h b/base/sequence_checker_impl.h
new file mode 100644
index 0000000..ccd1198
--- /dev/null
+++ b/base/sequence_checker_impl.h
@@ -0,0 +1,58 @@
+// 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.
+
+#ifndef BASE_SEQUENCE_CHECKER_IMPL_H_
+#define BASE_SEQUENCE_CHECKER_IMPL_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/synchronization/lock.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.
+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();
+
+ // 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;
+
+ // 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);
+
+ private:
+ // Guards all variables below.
+ mutable Lock lock_;
+ scoped_refptr<SequencedTaskRunner> sequenced_task_runner_;
+ // Used if |sequenced_task_runner_| is NULL.
+ ThreadCheckerImpl thread_checker_;
+
+ DISALLOW_COPY_AND_ASSIGN(SequenceCheckerImpl);
+};
+
+} // namespace base
+
+#endif // BASE_SEQUENCE_CHECKER_IMPL_H_
diff --git a/base/sequence_checker_impl_unittest.cc b/base/sequence_checker_impl_unittest.cc
new file mode 100644
index 0000000..4e601b0
--- /dev/null
+++ b/base/sequence_checker_impl_unittest.cc
@@ -0,0 +1,218 @@
+// 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
new file mode 100644
index 0000000..4fc3027
--- /dev/null
+++ b/base/sequence_checker_unittest.cc
@@ -0,0 +1,29 @@
+// 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.h"
+
+#include <cstddef>
+
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "base/test/null_task_runner.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+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();
+}
+
+} // namespace
+
+} // namespace base
diff --git a/base/test/null_task_runner.cc b/base/test/null_task_runner.cc
new file mode 100644
index 0000000..bf43e6d
--- /dev/null
+++ b/base/test/null_task_runner.cc
@@ -0,0 +1,31 @@
+// 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/test/null_task_runner.h"
+
+namespace base {
+
+NullTaskRunner::NullTaskRunner() {}
+
+NullTaskRunner::~NullTaskRunner() {}
+
+bool NullTaskRunner::PostDelayedTask(
+ const tracked_objects::Location& from_here,
+ const base::Closure& task,
+ base::TimeDelta delay) {
+ return false;
+}
+
+bool NullTaskRunner::PostNonNestableDelayedTask(
+ const tracked_objects::Location& from_here,
+ const base::Closure& task,
+ base::TimeDelta delay) {
+ return false;
+}
+
+bool NullTaskRunner::RunsTasksOnCurrentThread() const {
+ return true;
+}
+
+} // namespace
diff --git a/base/test/null_task_runner.h b/base/test/null_task_runner.h
new file mode 100644
index 0000000..d6390e5
--- /dev/null
+++ b/base/test/null_task_runner.h
@@ -0,0 +1,34 @@
+// 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/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/single_thread_task_runner.h"
+
+namespace base {
+
+// Helper class for tests that need to provide an implementation of a
+// *TaskRunner class but don't actually care about tasks being run.
+
+class NullTaskRunner : public base::SingleThreadTaskRunner {
+ public:
+ NullTaskRunner();
+
+ virtual bool PostDelayedTask(const tracked_objects::Location& from_here,
+ const base::Closure& task,
+ base::TimeDelta delay) OVERRIDE;
+ virtual bool PostNonNestableDelayedTask(
+ const tracked_objects::Location& from_here,
+ const base::Closure& task,
+ base::TimeDelta delay) OVERRIDE;
+ // Always returns true to avoid triggering DCHECKs.
+ virtual bool RunsTasksOnCurrentThread() const OVERRIDE;
+
+ protected:
+ virtual ~NullTaskRunner();
+
+ DISALLOW_COPY_AND_ASSIGN(NullTaskRunner);
+};
+
+} // namespace