Commit e329cb9d authored by Eric Seckler's avatar Eric Seckler Committed by Commit Bot

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: default avatarSami Kyöstilä <skyostil@chromium.org>
Reviewed-by: default avatarAvi Drissman <avi@chromium.org>
Reviewed-by: default avatarFrançois Doray <fdoray@chromium.org>
Reviewed-by: default avatarAlex Clarke <alexclarke@chromium.org>
Cr-Commit-Position: refs/heads/master@{#586728}
parent 0527de47
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "base/bind_helpers.h" #include "base/bind_helpers.h"
#include "base/task/task_executor.h" #include "base/task/task_executor.h"
#include "base/task/test_task_traits_extension.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/scoped_task_environment.h"
#include "base/test/test_simple_task_runner.h" #include "base/test/test_simple_task_runner.h"
#include "build/build_config.h" #include "build/build_config.h"
...@@ -186,4 +187,9 @@ TEST_F(PostTaskTestWithExecutor, PostTaskToTaskExecutor) { ...@@ -186,4 +187,9 @@ TEST_F(PostTaskTestWithExecutor, PostTaskToTaskExecutor) {
} }
} }
TEST_F(PostTaskTestWithExecutor, RegisterExecutorTwice) {
EXPECT_DCHECK_DEATH(
RegisterTaskExecutor(TestTaskTraitsExtension::kExtensionId, &executor_));
}
} // namespace base } // namespace base
...@@ -93,9 +93,12 @@ constexpr typename GetterType::ValueType GetValueFromArgListImpl( ...@@ -93,9 +93,12 @@ constexpr typename GetterType::ValueType GetValueFromArgListImpl(
// Converts an argument of type ArgType into a value returned by // Converts an argument of type ArgType into a value returned by
// GetValueFromArgListImpl(). // GetValueFromArgListImpl().
// //
// |getter| may provide:
//
// ValueType GetDefaultValue(): // ValueType GetDefaultValue():
// Returns the value returned by GetValueFromArgListImpl() if none of its // 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> template <class GetterType, class... ArgTypes>
constexpr typename GetterType::ValueType GetValueFromArgList( constexpr typename GetterType::ValueType GetValueFromArgList(
GetterType getter, GetterType getter,
...@@ -117,6 +120,12 @@ struct EnumArgGetter { ...@@ -117,6 +120,12 @@ struct EnumArgGetter {
constexpr ValueType GetDefaultValue() const { return DefaultValue; } 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 // 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 // convertible to the provided ValidTraits type. To use, define a ValidTraits
// type like this: // type like this:
......
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
#include "components/tracing/common/trace_startup.h" #include "components/tracing/common/trace_startup.h"
#include "content/app/mojo/mojo_init.h" #include "content/app/mojo/mojo_init.h"
#include "content/browser/browser_process_sub_thread.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/browser/startup_data_impl.h"
#include "content/common/content_constants_internal.h" #include "content/common/content_constants_internal.h"
#include "content/common/url_schemes.h" #include "content/common/url_schemes.h"
...@@ -878,6 +879,10 @@ int ContentMainRunnerImpl::Run(bool start_service_manager_only) { ...@@ -878,6 +879,10 @@ int ContentMainRunnerImpl::Run(bool start_service_manager_only) {
base::TaskScheduler::Create("Browser"); 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(); delegate_->PreCreateMainMessageLoop();
#if defined(OS_WIN) #if defined(OS_WIN)
if (l10n_util::GetLocaleOverrides().empty()) { if (l10n_util::GetLocaleOverrides().empty()) {
......
// 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
...@@ -15,9 +15,11 @@ ...@@ -15,9 +15,11 @@
#include "base/logging.h" #include "base/logging.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/sequence_checker.h" #include "base/sequence_checker.h"
#include "base/task/task_executor.h"
#include "base/threading/platform_thread.h" #include "base/threading/platform_thread.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/content_browser_client.h" #include "content/public/browser/content_browser_client.h"
namespace content { namespace content {
...@@ -161,6 +163,66 @@ bool PostTaskHelper(BrowserThread::ID identifier, ...@@ -161,6 +163,66 @@ bool PostTaskHelper(BrowserThread::ID identifier,
} }
} }
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 } // namespace
BrowserThreadImpl::BrowserThreadImpl( BrowserThreadImpl::BrowserThreadImpl(
...@@ -339,4 +401,21 @@ BrowserThread::GetTaskRunnerForThread(ID identifier) { ...@@ -339,4 +401,21 @@ BrowserThread::GetTaskRunnerForThread(ID identifier) {
return g_task_runners.Get().proxies[identifier]; 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 } // namespace content
...@@ -39,6 +39,13 @@ class CONTENT_EXPORT BrowserThreadImpl : public BrowserThread { ...@@ -39,6 +39,13 @@ class CONTENT_EXPORT BrowserThreadImpl : public BrowserThread {
// |identifier|. // |identifier|.
static void ResetGlobalsForTesting(BrowserThread::ID 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: private:
// Restrict instantiation to BrowserProcessSubThread as it performs important // Restrict instantiation to BrowserProcessSubThread as it performs important
// initialization that shouldn't be bypassed (except by BrowserMainLoop for // initialization that shouldn't be bypassed (except by BrowserMainLoop for
......
...@@ -12,9 +12,13 @@ ...@@ -12,9 +12,13 @@
#include "base/run_loop.h" #include "base/run_loop.h"
#include "base/sequenced_task_runner_helpers.h" #include "base/sequenced_task_runner_helpers.h"
#include "base/single_thread_task_runner.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 "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
#include "content/browser/browser_process_sub_thread.h" #include "content/browser/browser_process_sub_thread.h"
#include "content/browser/browser_thread_impl.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 "content/public/test/test_browser_thread.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h" #include "testing/platform_test.h"
...@@ -33,6 +37,8 @@ class BrowserThreadTest : public testing::Test { ...@@ -33,6 +37,8 @@ class BrowserThreadTest : public testing::Test {
protected: protected:
void SetUp() override { void SetUp() override {
BrowserThreadImpl::CreateTaskExecutor();
ui_thread_ = std::make_unique<BrowserProcessSubThread>(BrowserThread::UI); ui_thread_ = std::make_unique<BrowserProcessSubThread>(BrowserThread::UI);
ui_thread_->Start(); ui_thread_->Start();
...@@ -51,6 +57,7 @@ class BrowserThreadTest : public testing::Test { ...@@ -51,6 +57,7 @@ class BrowserThreadTest : public testing::Test {
BrowserThreadImpl::ResetGlobalsForTesting(BrowserThread::UI); BrowserThreadImpl::ResetGlobalsForTesting(BrowserThread::UI);
BrowserThreadImpl::ResetGlobalsForTesting(BrowserThread::IO); BrowserThreadImpl::ResetGlobalsForTesting(BrowserThread::IO);
BrowserThreadImpl::ResetTaskExecutorForTesting();
} }
// Prepares this BrowserThreadTest for Release() to be invoked. |on_release| // Prepares this BrowserThreadTest for Release() to be invoked. |on_release|
...@@ -59,8 +66,9 @@ class BrowserThreadTest : public testing::Test { ...@@ -59,8 +66,9 @@ class BrowserThreadTest : public testing::Test {
on_release_ = std::move(on_release); on_release_ = std::move(on_release);
} }
static void BasicFunction(base::OnceClosure continuation) { static void BasicFunction(base::OnceClosure continuation,
EXPECT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::IO)); BrowserThread::ID target) {
EXPECT_TRUE(BrowserThread::CurrentlyOn(target));
std::move(continuation).Run(); std::move(continuation).Run();
} }
...@@ -87,7 +95,7 @@ class BrowserThreadTest : public testing::Test { ...@@ -87,7 +95,7 @@ class BrowserThreadTest : public testing::Test {
std::unique_ptr<BrowserProcessSubThread> ui_thread_; std::unique_ptr<BrowserProcessSubThread> ui_thread_;
std::unique_ptr<BrowserProcessSubThread> io_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 // 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 // run from the next call to Release(). mutable so it can be consumed from
// Release(). // Release().
...@@ -136,7 +144,17 @@ TEST_F(BrowserThreadTest, PostTask) { ...@@ -136,7 +144,17 @@ TEST_F(BrowserThreadTest, PostTask) {
base::RunLoop run_loop; base::RunLoop run_loop;
BrowserThread::PostTask( BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE, 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(); run_loop.Run();
} }
...@@ -161,11 +179,53 @@ TEST_F(BrowserThreadTest, PostTaskViaTaskRunner) { ...@@ -161,11 +179,53 @@ TEST_F(BrowserThreadTest, PostTaskViaTaskRunner) {
BrowserThread::GetTaskRunnerForThread(BrowserThread::IO); BrowserThread::GetTaskRunnerForThread(BrowserThread::IO);
base::RunLoop run_loop; base::RunLoop run_loop;
task_runner->PostTask( task_runner->PostTask(
FROM_HERE, FROM_HERE, base::BindOnce(&BasicFunction, run_loop.QuitWhenIdleClosure(),
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(); 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) { TEST_F(BrowserThreadTest, ReleaseViaTaskRunner) {
scoped_refptr<base::SingleThreadTaskRunner> task_runner = scoped_refptr<base::SingleThreadTaskRunner> task_runner =
BrowserThread::GetTaskRunnerForThread(BrowserThread::UI); BrowserThread::GetTaskRunnerForThread(BrowserThread::UI);
...@@ -176,6 +236,15 @@ TEST_F(BrowserThreadTest, ReleaseViaTaskRunner) { ...@@ -176,6 +236,15 @@ TEST_F(BrowserThreadTest, ReleaseViaTaskRunner) {
run_loop.Run(); 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) { TEST_F(BrowserThreadTest, PostTaskAndReply) {
// Most of the heavy testing for PostTaskAndReply() is done inside the // Most of the heavy testing for PostTaskAndReply() is done inside the
// task runner test. This just makes sure we get piped through at all. // task runner test. This just makes sure we get piped through at all.
...@@ -186,6 +255,16 @@ TEST_F(BrowserThreadTest, PostTaskAndReply) { ...@@ -186,6 +255,16 @@ TEST_F(BrowserThreadTest, PostTaskAndReply) {
run_loop.Run(); 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) { TEST_F(BrowserThreadTest, RunsTasksInCurrentSequencedDuringShutdown) {
bool did_shutdown = false; bool did_shutdown = false;
base::RunLoop loop; base::RunLoop loop;
......
...@@ -79,6 +79,8 @@ jumbo_source_set("browser_sources") { ...@@ -79,6 +79,8 @@ jumbo_source_set("browser_sources") {
"browser_plugin_guest_manager.cc", "browser_plugin_guest_manager.cc",
"browser_plugin_guest_manager.h", "browser_plugin_guest_manager.h",
"browser_ppapi_host.h", "browser_ppapi_host.h",
"browser_task_traits.cc",
"browser_task_traits.h",
"browser_thread.h", "browser_thread.h",
"browser_thread_delegate.h", "browser_thread_delegate.h",
"browser_url_handler.h", "browser_url_handler.h",
......
// 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
// 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_
...@@ -18,7 +18,6 @@ ...@@ -18,7 +18,6 @@
#include "base/task_runner_util.h" #include "base/task_runner_util.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "content/common/content_export.h" #include "content/common/content_export.h"
#include "content/public/browser/browser_thread.h"
namespace content { namespace content {
...@@ -35,25 +34,17 @@ class BrowserThreadImpl; ...@@ -35,25 +34,17 @@ class BrowserThreadImpl;
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// BrowserThread // BrowserThread
// //
// Utility functions for threads that are known by a browser-wide // Utility functions for threads that are known by a browser-wide name. For
// name. For example, there is one IO thread for the entire browser // example, there is one IO thread for the entire browser process, and various
// process, and various pieces of code find it useful to retrieve a // pieces of code find it useful to retrieve a pointer to the IO thread's
// pointer to the IO thread's message loop. // 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); // This class automatically handles the lifetime of different threads. You
// // should never need to cache pointers to MessageLoops, since they're not thread
// The return value is false if the task couldn't be posted because the target // safe.
// 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.
class CONTENT_EXPORT BrowserThread { class CONTENT_EXPORT BrowserThread {
public: public:
// An enumeration of the well-known threads. // An enumeration of the well-known threads.
...@@ -68,7 +59,7 @@ class CONTENT_EXPORT BrowserThread { ...@@ -68,7 +59,7 @@ class CONTENT_EXPORT BrowserThread {
IO, IO,
// NOTE: do not add new threads here. Instead you should just use // 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 // This identifier does not represent a thread. Instead it counts the
// number of well-known threads. Insert new well-known threads before this // number of well-known threads. Insert new well-known threads before this
...@@ -76,6 +67,9 @@ class CONTENT_EXPORT BrowserThread { ...@@ -76,6 +67,9 @@ class CONTENT_EXPORT BrowserThread {
ID_COUNT 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 // 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. // 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 // They return true iff the thread existed and the task was posted. Note that
...@@ -176,8 +170,12 @@ class CONTENT_EXPORT BrowserThread { ...@@ -176,8 +170,12 @@ class CONTENT_EXPORT BrowserThread {
// sets identifier to its ID. Otherwise returns false. // sets identifier to its ID. Otherwise returns false.
static bool GetCurrentThreadIdentifier(ID* identifier) WARN_UNUSED_RESULT; static bool GetCurrentThreadIdentifier(ID* identifier) WARN_UNUSED_RESULT;
// Callers can hold on to a refcounted task runner beyond the lifetime // DEPRECATED: Please use the API described in browser_task_traits.h instead.
// of the thread. // 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( static scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunnerForThread(
ID identifier); ID identifier);
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "base/test/test_timeouts.h" #include "base/test/test_timeouts.h"
#include "base/threading/thread_restrictions.h" #include "base/threading/thread_restrictions.h"
#include "build/build_config.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/renderer_host/render_process_host_impl.h"
#include "content/browser/tracing/tracing_controller_impl.h" #include "content/browser/tracing/tracing_controller_impl.h"
#include "content/public/app/content_main.h" #include "content/public/app/content_main.h"
...@@ -313,6 +314,7 @@ void BrowserTestBase::SetUp() { ...@@ -313,6 +314,7 @@ void BrowserTestBase::SetUp() {
params.ui_task = ui_task.release(); params.ui_task = ui_task.release();
params.created_main_parts_closure = created_main_parts_closure.release(); params.created_main_parts_closure = created_main_parts_closure.release();
base::TaskScheduler::Create("Browser"); base::TaskScheduler::Create("Browser");
BrowserThreadImpl::CreateTaskExecutor();
// TODO(phajdan.jr): Check return code, http://crbug.com/374738 . // TODO(phajdan.jr): Check return code, http://crbug.com/374738 .
BrowserMain(params); BrowserMain(params);
#else #else
......
...@@ -725,6 +725,7 @@ test("content_browsertests") { ...@@ -725,6 +725,7 @@ test("content_browsertests") {
"../browser/blob_storage/blob_url_browsertest.cc", "../browser/blob_storage/blob_url_browsertest.cc",
"../browser/bookmarklet_browsertest.cc", "../browser/bookmarklet_browsertest.cc",
"../browser/browser_side_navigation_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/browsing_data_remover_impl_browsertest.cc",
"../browser/browsing_data/clear_site_data_handler_browsertest.cc", "../browser/browsing_data/clear_site_data_handler_browsertest.cc",
"../browser/browsing_data/conditional_cache_deletion_helper_browsertest.cc", "../browser/browsing_data/conditional_cache_deletion_helper_browsertest.cc",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment