summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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
-rw-r--r--content/public/test/test_browser_context.cc35
10 files changed, 492 insertions, 31 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
diff --git a/content/public/test/test_browser_context.cc b/content/public/test/test_browser_context.cc
index 2269812..ec47813 100644
--- a/content/public/test/test_browser_context.cc
+++ b/content/public/test/test_browser_context.cc
@@ -5,6 +5,7 @@
#include "content/public/test/test_browser_context.h"
#include "base/file_path.h"
+#include "base/test/null_task_runner.h"
#include "content/public/test/mock_resource_context.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h"
@@ -13,39 +14,11 @@
namespace {
-// A silly class to satisfy net::URLRequestsContextGetter requirement
-// for a task runner. Threading requirements don't matter for this
-// test scaffolding.
-class AnyThreadNonTaskRunner : public base::SingleThreadTaskRunner {
- public:
- virtual bool RunsTasksOnCurrentThread() const OVERRIDE {
- return true;
- }
-
- virtual bool PostDelayedTask(const tracked_objects::Location& from_here,
- const base::Closure& task,
- base::TimeDelta delay) OVERRIDE {
- NOTREACHED();
- return false;
- }
-
- virtual bool PostNonNestableDelayedTask(
- const tracked_objects::Location& from_here,
- const base::Closure& task,
- base::TimeDelta delay) OVERRIDE {
- NOTREACHED();
- return false;
- }
-
- private:
- virtual ~AnyThreadNonTaskRunner() {}
-};
-
class TestContextURLRequestContextGetter : public net::URLRequestContextGetter {
public:
explicit TestContextURLRequestContextGetter(net::URLRequestContext* context)
: context_(context),
- any_thread_non_task_runner_(new AnyThreadNonTaskRunner) {
+ null_task_runner_(new base::NullTaskRunner) {
}
virtual net::URLRequestContext* GetURLRequestContext() OVERRIDE {
@@ -54,14 +27,14 @@ class TestContextURLRequestContextGetter : public net::URLRequestContextGetter {
virtual scoped_refptr<base::SingleThreadTaskRunner>
GetNetworkTaskRunner() const OVERRIDE {
- return any_thread_non_task_runner_;
+ return null_task_runner_;
}
private:
virtual ~TestContextURLRequestContextGetter() {}
net::URLRequestContext* context_;
- scoped_refptr<base::SingleThreadTaskRunner> any_thread_non_task_runner_;
+ scoped_refptr<base::SingleThreadTaskRunner> null_task_runner_;
};
} // namespace