content: Add a TaskTraits extension and TaskExecutor for BrowserThreads.
This allows using //base/task/post_task.h for posting tasks to a
BrowserThread by specifying a BrowserThread::ID as a task trait.
Also adds a content::NonNestable task trait to support non-nestable
tasks in base::PostTaskWithTraits.
In the future, we will add further traits to facilitate scheduling
tasks onto different SequenceManager queues on the UI thread, see:
https://docs.google.com/document/d/1z1BDq9vzcEpkhN9LSPF5XMnZ0kLJ8mWWkNAi4OI7cos/edit?usp=sharing
Bug: 867421, 863341, 878356
Change-Id: Id8b7bc2e374917ceb421c7f6139790e6f1457511
Reviewed-on: https://chromium-review.googlesource.com/1181364
Commit-Queue: Eric Seckler <eseckler@chromium.org>
Reviewed-by: Sami Kyöstilä <skyostil@chromium.org>
Reviewed-by: Avi Drissman <avi@chromium.org>
Reviewed-by: François Doray <fdoray@chromium.org>
Reviewed-by: Alex Clarke <alexclarke@chromium.org>
Cr-Commit-Position: refs/heads/master@{#586728}
diff --git a/base/task/post_task_unittest.cc b/base/task/post_task_unittest.cc
index 467fdcb0..37876de 100644
--- a/base/task/post_task_unittest.cc
+++ b/base/task/post_task_unittest.cc
@@ -7,6 +7,7 @@
#include "base/bind_helpers.h"
#include "base/task/task_executor.h"
#include "base/task/test_task_traits_extension.h"
+#include "base/test/gtest_util.h"
#include "base/test/scoped_task_environment.h"
#include "base/test/test_simple_task_runner.h"
#include "build/build_config.h"
@@ -186,4 +187,9 @@
}
}
+TEST_F(PostTaskTestWithExecutor, RegisterExecutorTwice) {
+ EXPECT_DCHECK_DEATH(
+ RegisterTaskExecutor(TestTaskTraitsExtension::kExtensionId, &executor_));
+}
+
} // namespace base
diff --git a/base/task/task_traits_details.h b/base/task/task_traits_details.h
index 11001e7..d916948 100644
--- a/base/task/task_traits_details.h
+++ b/base/task/task_traits_details.h
@@ -93,9 +93,12 @@
// Converts an argument of type ArgType into a value returned by
// GetValueFromArgListImpl().
//
+// |getter| may provide:
+//
// ValueType GetDefaultValue():
// Returns the value returned by GetValueFromArgListImpl() if none of its
-// arguments is of type ArgType.
+// arguments is of type ArgType. If this method is not provided, compilation
+// will fail when no argument of type ArgType is provided.
template <class GetterType, class... ArgTypes>
constexpr typename GetterType::ValueType GetValueFromArgList(
GetterType getter,
@@ -117,6 +120,12 @@
constexpr ValueType GetDefaultValue() const { return DefaultValue; }
};
+template <typename ArgType>
+struct RequiredEnumArgGetter {
+ using ValueType = ArgType;
+ constexpr ValueType GetValueFromArg(ArgType arg) const { return arg; }
+};
+
// Tests whether a given trait type is valid or invalid by testing whether it is
// convertible to the provided ValidTraits type. To use, define a ValidTraits
// type like this:
diff --git a/content/app/content_main_runner_impl.cc b/content/app/content_main_runner_impl.cc
index c9fd1a4..4caa237 100644
--- a/content/app/content_main_runner_impl.cc
+++ b/content/app/content_main_runner_impl.cc
@@ -42,6 +42,7 @@
#include "components/tracing/common/trace_startup.h"
#include "content/app/mojo/mojo_init.h"
#include "content/browser/browser_process_sub_thread.h"
+#include "content/browser/browser_thread_impl.h"
#include "content/browser/startup_data_impl.h"
#include "content/common/content_constants_internal.h"
#include "content/common/url_schemes.h"
@@ -878,6 +879,10 @@
base::TaskScheduler::Create("Browser");
}
+ // Register the TaskExecutor for posting task to the BrowserThreads. It is
+ // incorrect to post to a BrowserThread before this point.
+ BrowserThreadImpl::CreateTaskExecutor();
+
delegate_->PreCreateMainMessageLoop();
#if defined(OS_WIN)
if (l10n_util::GetLocaleOverrides().empty()) {
diff --git a/content/browser/browser_thread_browsertest.cc b/content/browser/browser_thread_browsertest.cc
new file mode 100644
index 0000000..25bf7fc
--- /dev/null
+++ b/content/browser/browser_thread_browsertest.cc
@@ -0,0 +1,51 @@
+// Copyright 2018 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/bind_helpers.h"
+#include "base/task/post_task.h"
+#include "base/test/gtest_util.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/test/content_browser_test.h"
+
+namespace content {
+
+class BrowserThreadPostTaskBeforeInitBrowserTest : public ContentBrowserTest {
+ protected:
+ void SetUp() override {
+ // This should fail because the TaskScheduler + TaskExecutor weren't created
+ // yet.
+ EXPECT_DCHECK_DEATH(base::PostTaskWithTraits(FROM_HERE, {BrowserThread::IO},
+ base::DoNothing()));
+
+ // Obtaining a TaskRunner should also fail.
+ EXPECT_DCHECK_DEATH(base::CreateTaskRunnerWithTraits({BrowserThread::IO}));
+
+ ContentBrowserTest::SetUp();
+ }
+};
+
+IN_PROC_BROWSER_TEST_F(BrowserThreadPostTaskBeforeInitBrowserTest,
+ ExpectFailures) {}
+
+class BrowserThreadPostTaskBeforeThreadCreationBrowserTest
+ : public ContentBrowserTest {
+ protected:
+ void CreatedBrowserMainParts(BrowserMainParts* browser_main_parts) override {
+ // This should fail because the IO thread hasn't been initialized yet.
+ EXPECT_DCHECK_DEATH(base::PostTaskWithTraits(FROM_HERE, {BrowserThread::IO},
+ base::DoNothing()));
+
+ // Obtaining a TaskRunner should work, because the TaskExecutor was
+ // registered already.
+ auto task_runner = base::CreateTaskRunnerWithTraits({BrowserThread::IO});
+ // But posting should still fail.
+ EXPECT_DCHECK_DEATH(task_runner->PostTask(FROM_HERE, base::DoNothing()));
+ }
+};
+
+IN_PROC_BROWSER_TEST_F(BrowserThreadPostTaskBeforeThreadCreationBrowserTest,
+ ExpectFailures) {}
+
+} // namespace content
diff --git a/content/browser/browser_thread_impl.cc b/content/browser/browser_thread_impl.cc
index 4443c7b..15856a2 100644
--- a/content/browser/browser_thread_impl.cc
+++ b/content/browser/browser_thread_impl.cc
@@ -15,9 +15,11 @@
#include "base/logging.h"
#include "base/macros.h"
#include "base/sequence_checker.h"
+#include "base/task/task_executor.h"
#include "base/threading/platform_thread.h"
#include "base/time/time.h"
#include "build/build_config.h"
+#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/content_browser_client.h"
namespace content {
@@ -161,6 +163,66 @@
}
}
+class BrowserThreadTaskExecutor : public base::TaskExecutor {
+ public:
+ BrowserThreadTaskExecutor() {}
+ ~BrowserThreadTaskExecutor() override {}
+
+ // base::TaskExecutor implementation.
+ bool PostDelayedTaskWithTraits(const base::Location& from_here,
+ const base::TaskTraits& traits,
+ base::OnceClosure task,
+ base::TimeDelta delay) override {
+ return PostTaskHelper(
+ GetBrowserThreadIdentifier(traits), from_here, std::move(task), delay,
+ traits.GetExtension<BrowserTaskTraitsExtension>().nestable());
+ }
+
+ scoped_refptr<base::TaskRunner> CreateTaskRunnerWithTraits(
+ const base::TaskTraits& traits) override {
+ return GetTaskRunnerForThread(GetBrowserThreadIdentifier(traits));
+ }
+
+ scoped_refptr<base::SequencedTaskRunner> CreateSequencedTaskRunnerWithTraits(
+ const base::TaskTraits& traits) override {
+ return GetTaskRunnerForThread(GetBrowserThreadIdentifier(traits));
+ }
+
+ scoped_refptr<base::SingleThreadTaskRunner>
+ CreateSingleThreadTaskRunnerWithTraits(
+ const base::TaskTraits& traits,
+ base::SingleThreadTaskRunnerThreadMode thread_mode) override {
+ DCHECK_EQ(thread_mode, base::SingleThreadTaskRunnerThreadMode::SHARED);
+ return GetTaskRunnerForThread(GetBrowserThreadIdentifier(traits));
+ }
+
+#if defined(OS_WIN)
+ scoped_refptr<base::SingleThreadTaskRunner> CreateCOMSTATaskRunnerWithTraits(
+ const base::TaskTraits& traits,
+ base::SingleThreadTaskRunnerThreadMode thread_mode) override {
+ DCHECK_EQ(GetBrowserThreadIdentifier(traits), BrowserThread::UI);
+ return CreateSingleThreadTaskRunnerWithTraits(traits, thread_mode);
+ }
+#endif // defined(OS_WIN)
+
+ private:
+ BrowserThread::ID GetBrowserThreadIdentifier(const base::TaskTraits& traits) {
+ DCHECK_EQ(traits.extension_id(), BrowserTaskTraitsExtension::kExtensionId);
+ BrowserThread::ID id =
+ traits.GetExtension<BrowserTaskTraitsExtension>().browser_thread();
+ DCHECK_LT(id, BrowserThread::ID_COUNT);
+ return id;
+ }
+
+ scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunnerForThread(
+ BrowserThread::ID identifier) {
+ return g_task_runners.Get().proxies[identifier];
+ }
+};
+
+// |g_browser_thread_task_executor| is intentionally leaked on shutdown.
+BrowserThreadTaskExecutor* g_browser_thread_task_executor = nullptr;
+
} // namespace
BrowserThreadImpl::BrowserThreadImpl(
@@ -339,4 +401,21 @@
return g_task_runners.Get().proxies[identifier];
}
+// static
+void BrowserThreadImpl::CreateTaskExecutor() {
+ DCHECK(!g_browser_thread_task_executor);
+ g_browser_thread_task_executor = new BrowserThreadTaskExecutor();
+ base::RegisterTaskExecutor(BrowserTaskTraitsExtension::kExtensionId,
+ g_browser_thread_task_executor);
+}
+
+// static
+void BrowserThreadImpl::ResetTaskExecutorForTesting() {
+ DCHECK(g_browser_thread_task_executor);
+ base::UnregisterTaskExecutorForTesting(
+ BrowserTaskTraitsExtension::kExtensionId);
+ delete g_browser_thread_task_executor;
+ g_browser_thread_task_executor = nullptr;
+}
+
} // namespace content
diff --git a/content/browser/browser_thread_impl.h b/content/browser/browser_thread_impl.h
index cd0759c..5789a29 100644
--- a/content/browser/browser_thread_impl.h
+++ b/content/browser/browser_thread_impl.h
@@ -39,6 +39,13 @@
// |identifier|.
static void ResetGlobalsForTesting(BrowserThread::ID identifier);
+ // Creates and registers a TaskExecutor that facilitates posting tasks to a
+ // BrowserThread via //base/task/post_task.h.
+ static void CreateTaskExecutor();
+
+ // Unregister and delete the TaskExecutor after a test.
+ static void ResetTaskExecutorForTesting();
+
private:
// Restrict instantiation to BrowserProcessSubThread as it performs important
// initialization that shouldn't be bypassed (except by BrowserMainLoop for
diff --git a/content/browser/browser_thread_unittest.cc b/content/browser/browser_thread_unittest.cc
index cf5b1635..f27b5b9 100644
--- a/content/browser/browser_thread_unittest.cc
+++ b/content/browser/browser_thread_unittest.cc
@@ -12,9 +12,13 @@
#include "base/run_loop.h"
#include "base/sequenced_task_runner_helpers.h"
#include "base/single_thread_task_runner.h"
+#include "base/task/post_task.h"
+#include "base/test/scoped_task_environment.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "build/build_config.h"
#include "content/browser/browser_process_sub_thread.h"
#include "content/browser/browser_thread_impl.h"
+#include "content/public/browser/browser_task_traits.h"
#include "content/public/test/test_browser_thread.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
@@ -33,6 +37,8 @@
protected:
void SetUp() override {
+ BrowserThreadImpl::CreateTaskExecutor();
+
ui_thread_ = std::make_unique<BrowserProcessSubThread>(BrowserThread::UI);
ui_thread_->Start();
@@ -51,6 +57,7 @@
BrowserThreadImpl::ResetGlobalsForTesting(BrowserThread::UI);
BrowserThreadImpl::ResetGlobalsForTesting(BrowserThread::IO);
+ BrowserThreadImpl::ResetTaskExecutorForTesting();
}
// Prepares this BrowserThreadTest for Release() to be invoked. |on_release|
@@ -59,8 +66,9 @@
on_release_ = std::move(on_release);
}
- static void BasicFunction(base::OnceClosure continuation) {
- EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ static void BasicFunction(base::OnceClosure continuation,
+ BrowserThread::ID target) {
+ EXPECT_TRUE(BrowserThread::CurrentlyOn(target));
std::move(continuation).Run();
}
@@ -87,7 +95,7 @@
std::unique_ptr<BrowserProcessSubThread> ui_thread_;
std::unique_ptr<BrowserProcessSubThread> io_thread_;
- base::MessageLoop loop_;
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
// Must be set before Release() to verify the deletion is intentional. Will be
// run from the next call to Release(). mutable so it can be consumed from
// Release().
@@ -136,7 +144,17 @@
base::RunLoop run_loop;
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
- base::BindOnce(&BasicFunction, run_loop.QuitWhenIdleClosure()));
+ base::BindOnce(&BasicFunction, run_loop.QuitWhenIdleClosure(),
+ BrowserThread::IO));
+ run_loop.Run();
+}
+
+TEST_F(BrowserThreadTest, PostTaskWithTraits) {
+ base::RunLoop run_loop;
+ EXPECT_TRUE(base::PostTaskWithTraits(
+ FROM_HERE, {BrowserThread::IO, NonNestable()},
+ base::BindOnce(&BasicFunction, run_loop.QuitWhenIdleClosure(),
+ BrowserThread::IO)));
run_loop.Run();
}
@@ -161,11 +179,53 @@
BrowserThread::GetTaskRunnerForThread(BrowserThread::IO);
base::RunLoop run_loop;
task_runner->PostTask(
- FROM_HERE,
- base::BindOnce(&BasicFunction, run_loop.QuitWhenIdleClosure()));
+ FROM_HERE, base::BindOnce(&BasicFunction, run_loop.QuitWhenIdleClosure(),
+ BrowserThread::IO));
run_loop.Run();
}
+TEST_F(BrowserThreadTest, PostTaskViaTaskRunnerWithTraits) {
+ scoped_refptr<base::TaskRunner> task_runner =
+ base::CreateTaskRunnerWithTraits({BrowserThread::IO});
+ base::RunLoop run_loop;
+ EXPECT_TRUE(task_runner->PostTask(
+ FROM_HERE, base::BindOnce(&BasicFunction, run_loop.QuitWhenIdleClosure(),
+ BrowserThread::IO)));
+ run_loop.Run();
+}
+
+TEST_F(BrowserThreadTest, PostTaskViaSequencedTaskRunnerWithTraits) {
+ scoped_refptr<base::SequencedTaskRunner> task_runner =
+ base::CreateSequencedTaskRunnerWithTraits({BrowserThread::IO});
+ base::RunLoop run_loop;
+ EXPECT_TRUE(task_runner->PostTask(
+ FROM_HERE, base::BindOnce(&BasicFunction, run_loop.QuitWhenIdleClosure(),
+ BrowserThread::IO)));
+ run_loop.Run();
+}
+
+TEST_F(BrowserThreadTest, PostTaskViaSingleThreadTaskRunnerWithTraits) {
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner =
+ base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::IO});
+ base::RunLoop run_loop;
+ EXPECT_TRUE(task_runner->PostTask(
+ FROM_HERE, base::BindOnce(&BasicFunction, run_loop.QuitWhenIdleClosure(),
+ BrowserThread::IO)));
+ run_loop.Run();
+}
+
+#if defined(OS_WIN)
+TEST_F(BrowserThreadTest, PostTaskViaCOMSTATaskRunnerWithTraits) {
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner =
+ base::CreateCOMSTATaskRunnerWithTraits({BrowserThread::UI});
+ base::RunLoop run_loop;
+ EXPECT_TRUE(task_runner->PostTask(
+ FROM_HERE, base::BindOnce(&BasicFunction, run_loop.QuitWhenIdleClosure(),
+ BrowserThread::UI)));
+ run_loop.Run();
+}
+#endif // defined(OS_WIN)
+
TEST_F(BrowserThreadTest, ReleaseViaTaskRunner) {
scoped_refptr<base::SingleThreadTaskRunner> task_runner =
BrowserThread::GetTaskRunnerForThread(BrowserThread::UI);
@@ -176,6 +236,15 @@
run_loop.Run();
}
+TEST_F(BrowserThreadTest, ReleaseViaTaskRunnerWithTraits) {
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner =
+ base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::UI});
+ base::RunLoop run_loop;
+ ExpectRelease(run_loop.QuitWhenIdleClosure());
+ task_runner->ReleaseSoon(FROM_HERE, this);
+ run_loop.Run();
+}
+
TEST_F(BrowserThreadTest, PostTaskAndReply) {
// Most of the heavy testing for PostTaskAndReply() is done inside the
// task runner test. This just makes sure we get piped through at all.
@@ -186,6 +255,16 @@
run_loop.Run();
}
+TEST_F(BrowserThreadTest, PostTaskAndReplyWithTraits) {
+ // Most of the heavy testing for PostTaskAndReply() is done inside the
+ // task runner test. This just makes sure we get piped through at all.
+ base::RunLoop run_loop;
+ ASSERT_TRUE(base::PostTaskWithTraitsAndReply(FROM_HERE, {BrowserThread::IO},
+ base::DoNothing(),
+ run_loop.QuitWhenIdleClosure()));
+ run_loop.Run();
+}
+
TEST_F(BrowserThreadTest, RunsTasksInCurrentSequencedDuringShutdown) {
bool did_shutdown = false;
base::RunLoop loop;
diff --git a/content/public/browser/BUILD.gn b/content/public/browser/BUILD.gn
index dac4d10..1ebae0a 100644
--- a/content/public/browser/BUILD.gn
+++ b/content/public/browser/BUILD.gn
@@ -79,6 +79,8 @@
"browser_plugin_guest_manager.cc",
"browser_plugin_guest_manager.h",
"browser_ppapi_host.h",
+ "browser_task_traits.cc",
+ "browser_task_traits.h",
"browser_thread.h",
"browser_thread_delegate.h",
"browser_url_handler.h",
diff --git a/content/public/browser/browser_task_traits.cc b/content/public/browser/browser_task_traits.cc
new file mode 100644
index 0000000..311902e
--- /dev/null
+++ b/content/public/browser/browser_task_traits.cc
@@ -0,0 +1,12 @@
+// Copyright 2018 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 "content/public/browser/browser_task_traits.h"
+
+namespace content {
+
+// static
+constexpr uint8_t BrowserTaskTraitsExtension::kExtensionId;
+
+} // namespace content
diff --git a/content/public/browser/browser_task_traits.h b/content/public/browser/browser_task_traits.h
new file mode 100644
index 0000000..8ccee9d9
--- /dev/null
+++ b/content/public/browser/browser_task_traits.h
@@ -0,0 +1,102 @@
+// Copyright 2018 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 CONTENT_PUBLIC_BROWSER_BROWSER_TASK_TRAITS_H_
+#define CONTENT_PUBLIC_BROWSER_BROWSER_TASK_TRAITS_H_
+
+#include "base/task/task_traits.h"
+#include "base/task/task_traits_extension.h"
+#include "content/common/content_export.h"
+#include "content/public/browser/browser_thread.h"
+
+namespace content {
+
+// Tasks with this trait will not be executed inside a nested RunLoop.
+//
+// Note: This should rarely be required. Drivers of nested loops should instead
+// make sure to be reentrant when allowing nested application tasks (also rare).
+//
+// TODO(https://crbug.com/876272): Investigate removing this trait -- and any
+// logic for deferred tasks in MessageLoop.
+struct NonNestable {};
+
+// TaskTraits for running tasks on the browser threads.
+//
+// These traits enable the use of the //base/task/post_task.h APIs to post tasks
+// to a BrowserThread.
+//
+// To post a task to the UI thread (analogous for IO thread):
+// base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI}, task);
+//
+// To obtain a TaskRunner for the UI thread (analogous for the IO thread):
+// base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::UI});
+//
+// See //base/task/post_task.h for more detailed documentation.
+//
+// Posting to a BrowserThread must only be done after it was initialized (ref.
+// BrowserMainLoop::CreateThreads() phase).
+class CONTENT_EXPORT BrowserTaskTraitsExtension {
+ public:
+ static constexpr uint8_t kExtensionId =
+ base::TaskTraitsExtensionStorage::kFirstEmbedderExtensionId;
+
+ struct ValidTrait {
+ ValidTrait(BrowserThread::ID) {}
+ ValidTrait(NonNestable) {}
+ };
+
+ template <
+ class... ArgTypes,
+ class CheckArgumentsAreValid = std::enable_if_t<
+ base::trait_helpers::AreValidTraits<ValidTrait, ArgTypes...>::value>>
+ constexpr BrowserTaskTraitsExtension(ArgTypes... args)
+ : browser_thread_(base::trait_helpers::GetValueFromArgList(
+ base::trait_helpers::RequiredEnumArgGetter<BrowserThread::ID>(),
+ args...)),
+ nestable_(!base::trait_helpers::GetValueFromArgList(
+ base::trait_helpers::BooleanArgGetter<NonNestable>(),
+ args...)) {}
+
+ constexpr base::TaskTraitsExtensionStorage Serialize() const {
+ static_assert(8 == sizeof(BrowserTaskTraitsExtension),
+ "Update Serialize() and Parse() when changing "
+ "BrowserTaskTraitsExtension");
+ return {kExtensionId,
+ {static_cast<uint8_t>(browser_thread_),
+ static_cast<uint8_t>(nestable_)}};
+ }
+
+ static const BrowserTaskTraitsExtension Parse(
+ const base::TaskTraitsExtensionStorage& extension) {
+ return BrowserTaskTraitsExtension(
+ static_cast<BrowserThread::ID>(extension.data[0]),
+ static_cast<bool>(extension.data[1]));
+ }
+
+ constexpr BrowserThread::ID browser_thread() const { return browser_thread_; }
+
+ // Returns true if tasks with these traits may run in a nested RunLoop.
+ constexpr bool nestable() const { return nestable_; }
+
+ private:
+ BrowserTaskTraitsExtension(BrowserThread::ID browser_thread, bool nestable)
+ : browser_thread_(browser_thread), nestable_(nestable) {}
+
+ BrowserThread::ID browser_thread_;
+ bool nestable_;
+};
+
+template <class... ArgTypes,
+ class = std::enable_if_t<base::trait_helpers::AreValidTraits<
+ BrowserTaskTraitsExtension::ValidTrait,
+ ArgTypes...>::value>>
+constexpr base::TaskTraitsExtensionStorage MakeTaskTraitsExtension(
+ ArgTypes&&... args) {
+ return BrowserTaskTraitsExtension(std::forward<ArgTypes>(args)...)
+ .Serialize();
+}
+
+} // namespace content
+
+#endif // CONTENT_PUBLIC_BROWSER_BROWSER_TASK_TRAITS_H_
diff --git a/content/public/browser/browser_thread.h b/content/public/browser/browser_thread.h
index 5d43972..159bc7f 100644
--- a/content/public/browser/browser_thread.h
+++ b/content/public/browser/browser_thread.h
@@ -18,7 +18,6 @@
#include "base/task_runner_util.h"
#include "base/time/time.h"
#include "content/common/content_export.h"
-#include "content/public/browser/browser_thread.h"
namespace content {
@@ -35,25 +34,17 @@
///////////////////////////////////////////////////////////////////////////////
// BrowserThread
//
-// Utility functions for threads that are known by a browser-wide
-// name. For example, there is one IO thread for the entire browser
-// process, and various pieces of code find it useful to retrieve a
-// pointer to the IO thread's message loop.
+// Utility functions for threads that are known by a browser-wide name. For
+// example, there is one IO thread for the entire browser process, and various
+// pieces of code find it useful to retrieve a pointer to the IO thread's
+// message loop.
//
-// Invoke a task by thread ID:
+// See browser_task_traits.h for posting Tasks to a BrowserThread.
+// TODO(https://crbug.com/878356): Replace uses with base's post_task.h API.
//
-// BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, task);
-//
-// The return value is false if the task couldn't be posted because the target
-// thread doesn't exist. If this could lead to data loss, you need to check the
-// result and restructure the code to ensure it doesn't occur.
-//
-// This class automatically handles the lifetime of different threads.
-// It's always safe to call PostTask on any thread. If it's not yet created,
-// the task is deleted. There are no race conditions. If the thread that the
-// task is posted to is guaranteed to outlive the current thread, then no locks
-// are used. You should never need to cache pointers to MessageLoops, since
-// they're not thread safe.
+// This class automatically handles the lifetime of different threads. You
+// should never need to cache pointers to MessageLoops, since they're not thread
+// safe.
class CONTENT_EXPORT BrowserThread {
public:
// An enumeration of the well-known threads.
@@ -68,7 +59,7 @@
IO,
// NOTE: do not add new threads here. Instead you should just use
- // base::Create*TaskRunnerWithTraits.
+ // base::Create*TaskRunnerWithTraits to run tasks on the TaskScheduler.
// This identifier does not represent a thread. Instead it counts the
// number of well-known threads. Insert new well-known threads before this
@@ -76,6 +67,9 @@
ID_COUNT
};
+ // DEPRECATED: Please use the API described in browser_task_traits.h instead.
+ // TODO(https://crbug.com/878356): Replace uses with base::PostTaskWithTraits.
+ //
// These are the same methods in message_loop.h, but are guaranteed to either
// get posted to the MessageLoop if it's still alive, or be deleted otherwise.
// They return true iff the thread existed and the task was posted. Note that
@@ -176,8 +170,12 @@
// sets identifier to its ID. Otherwise returns false.
static bool GetCurrentThreadIdentifier(ID* identifier) WARN_UNUSED_RESULT;
- // Callers can hold on to a refcounted task runner beyond the lifetime
- // of the thread.
+ // DEPRECATED: Please use the API described in browser_task_traits.h instead.
+ // TODO(https://crbug.com/878356): Replace uses with
+ // base::Create*TaskRunnerWithTraits.
+ //
+ // Callers can hold on to a refcounted task runner beyond the lifetime of the
+ // thread.
static scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunnerForThread(
ID identifier);
diff --git a/content/public/test/browser_test_base.cc b/content/public/test/browser_test_base.cc
index 5b84ebd..cb5fcf4c 100644
--- a/content/public/test/browser_test_base.cc
+++ b/content/public/test/browser_test_base.cc
@@ -23,6 +23,7 @@
#include "base/test/test_timeouts.h"
#include "base/threading/thread_restrictions.h"
#include "build/build_config.h"
+#include "content/browser/browser_thread_impl.h"
#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/browser/tracing/tracing_controller_impl.h"
#include "content/public/app/content_main.h"
@@ -313,6 +314,7 @@
params.ui_task = ui_task.release();
params.created_main_parts_closure = created_main_parts_closure.release();
base::TaskScheduler::Create("Browser");
+ BrowserThreadImpl::CreateTaskExecutor();
// TODO(phajdan.jr): Check return code, http://crbug.com/374738 .
BrowserMain(params);
#else
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 31ea8cc..804367e 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -725,6 +725,7 @@
"../browser/blob_storage/blob_url_browsertest.cc",
"../browser/bookmarklet_browsertest.cc",
"../browser/browser_side_navigation_browsertest.cc",
+ "../browser/browser_thread_browsertest.cc",
"../browser/browsing_data/browsing_data_remover_impl_browsertest.cc",
"../browser/browsing_data/clear_site_data_handler_browsertest.cc",
"../browser/browsing_data/conditional_cache_deletion_helper_browsertest.cc",