Commit 49e3cd09 authored by Gabriel Charette's avatar Gabriel Charette Committed by Commit Bot

Introduce content::GetUIThreadTaskRunner() and its IO counterpart

As agreed upon in design doc @
https://docs.google.com/document/d/1tssusPykvx3g0gvbvU4HxGyn3MjJlIylnsH13-Tv6s4/edit?ts=5e1c66d5&pli=1#bookmark=id.ll79iqi5rlpp

base::ThreadPool counterpart to move away from post_task.h is @
https://chromium-review.googlesource.com/c/chromium/src/+/1977964

API usage migration will be done in a follow-up mega CL.
This CL at least uses it in its own tests.

See https://chromium-review.googlesource.com/c/chromium/src/+/2015655
for how this will look in practice for a few callsites.

Bug: 1026641
Change-Id: I98771fd68a513bf0a4776672a8d75fcbbb200bea
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2014055
Commit-Queue: Gabriel Charette <gab@chromium.org>
Reviewed-by: default avatarAlexander Timin <altimin@chromium.org>
Reviewed-by: default avatarFrançois Doray <fdoray@chromium.org>
Reviewed-by: default avatarDarin Fisher <darin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#735734}
parent 72e58360
...@@ -45,7 +45,8 @@ TaskExecutor* GetTaskExecutorForTraits(const TaskTraits& traits) { ...@@ -45,7 +45,8 @@ TaskExecutor* GetTaskExecutorForTraits(const TaskTraits& traits) {
traits.extension_id() != TaskTraitsExtensionStorage::kInvalidExtensionId; traits.extension_id() != TaskTraitsExtensionStorage::kInvalidExtensionId;
DCHECK(has_extension ^ traits.use_thread_pool()) DCHECK(has_extension ^ traits.use_thread_pool())
<< "A destination (e.g. ThreadPool or BrowserThread) must be specified " << "A destination (e.g. ThreadPool or BrowserThread) must be specified "
"to use the post_task.h API."; "to use the post_task.h API. However, you should prefer the direct "
"thread_pool.h or browser_thread.h APIs in new code.";
if (traits.use_thread_pool()) { if (traits.use_thread_pool()) {
DCHECK(ThreadPoolInstance::Get()) DCHECK(ThreadPoolInstance::Get())
......
...@@ -84,6 +84,16 @@ BrowserThreadGlobals& GetBrowserThreadGlobals() { ...@@ -84,6 +84,16 @@ BrowserThreadGlobals& GetBrowserThreadGlobals() {
} // namespace } // namespace
scoped_refptr<base::SingleThreadTaskRunner> GetUIThreadTaskRunner(
const BrowserTaskTraits& traits) {
return BrowserTaskExecutor::GetUIThreadTaskRunner(traits);
}
scoped_refptr<base::SingleThreadTaskRunner> GetIOThreadTaskRunner(
const BrowserTaskTraits& traits) {
return BrowserTaskExecutor::GetIOThreadTaskRunner(traits);
}
BrowserThreadImpl::BrowserThreadImpl( BrowserThreadImpl::BrowserThreadImpl(
ID identifier, ID identifier,
scoped_refptr<base::SingleThreadTaskRunner> task_runner) scoped_refptr<base::SingleThreadTaskRunner> task_runner)
......
...@@ -165,8 +165,7 @@ class UIThreadDestructionObserver ...@@ -165,8 +165,7 @@ class UIThreadDestructionObserver
explicit UIThreadDestructionObserver(bool* did_shutdown, explicit UIThreadDestructionObserver(bool* did_shutdown,
base::OnceClosure callback) base::OnceClosure callback)
: callback_task_runner_(base::ThreadTaskRunnerHandle::Get()), : callback_task_runner_(base::ThreadTaskRunnerHandle::Get()),
ui_task_runner_( ui_task_runner_(GetUIThreadTaskRunner({})),
base::CreateSingleThreadTaskRunner({BrowserThread::UI})),
callback_(std::move(callback)), callback_(std::move(callback)),
did_shutdown_(did_shutdown) { did_shutdown_(did_shutdown) {
ui_task_runner_->PostTask(FROM_HERE, base::BindOnce(&Watch, this)); ui_task_runner_->PostTask(FROM_HERE, base::BindOnce(&Watch, this));
...@@ -223,8 +222,7 @@ TEST_F(BrowserThreadTest, ReleasedOnCorrectThread) { ...@@ -223,8 +222,7 @@ TEST_F(BrowserThreadTest, ReleasedOnCorrectThread) {
} }
TEST_F(BrowserThreadTest, PostTaskViaTaskRunner) { TEST_F(BrowserThreadTest, PostTaskViaTaskRunner) {
scoped_refptr<base::TaskRunner> task_runner = scoped_refptr<base::TaskRunner> task_runner = GetIOThreadTaskRunner({});
base::CreateTaskRunner({BrowserThread::IO});
base::RunLoop run_loop; base::RunLoop run_loop;
EXPECT_TRUE(task_runner->PostTask( EXPECT_TRUE(task_runner->PostTask(
FROM_HERE, base::BindOnce(&BasicFunction, run_loop.QuitWhenIdleClosure(), FROM_HERE, base::BindOnce(&BasicFunction, run_loop.QuitWhenIdleClosure(),
...@@ -234,7 +232,7 @@ TEST_F(BrowserThreadTest, PostTaskViaTaskRunner) { ...@@ -234,7 +232,7 @@ TEST_F(BrowserThreadTest, PostTaskViaTaskRunner) {
TEST_F(BrowserThreadTest, PostTaskViaSequencedTaskRunner) { TEST_F(BrowserThreadTest, PostTaskViaSequencedTaskRunner) {
scoped_refptr<base::SequencedTaskRunner> task_runner = scoped_refptr<base::SequencedTaskRunner> task_runner =
base::CreateSequencedTaskRunner({BrowserThread::IO}); GetIOThreadTaskRunner({});
base::RunLoop run_loop; base::RunLoop run_loop;
EXPECT_TRUE(task_runner->PostTask( EXPECT_TRUE(task_runner->PostTask(
FROM_HERE, base::BindOnce(&BasicFunction, run_loop.QuitWhenIdleClosure(), FROM_HERE, base::BindOnce(&BasicFunction, run_loop.QuitWhenIdleClosure(),
...@@ -244,7 +242,7 @@ TEST_F(BrowserThreadTest, PostTaskViaSequencedTaskRunner) { ...@@ -244,7 +242,7 @@ TEST_F(BrowserThreadTest, PostTaskViaSequencedTaskRunner) {
TEST_F(BrowserThreadTest, PostTaskViaSingleThreadTaskRunner) { TEST_F(BrowserThreadTest, PostTaskViaSingleThreadTaskRunner) {
scoped_refptr<base::SingleThreadTaskRunner> task_runner = scoped_refptr<base::SingleThreadTaskRunner> task_runner =
base::CreateSingleThreadTaskRunner({BrowserThread::IO}); GetIOThreadTaskRunner({});
base::RunLoop run_loop; base::RunLoop run_loop;
EXPECT_TRUE(task_runner->PostTask( EXPECT_TRUE(task_runner->PostTask(
FROM_HERE, base::BindOnce(&BasicFunction, run_loop.QuitWhenIdleClosure(), FROM_HERE, base::BindOnce(&BasicFunction, run_loop.QuitWhenIdleClosure(),
...@@ -255,7 +253,7 @@ TEST_F(BrowserThreadTest, PostTaskViaSingleThreadTaskRunner) { ...@@ -255,7 +253,7 @@ TEST_F(BrowserThreadTest, PostTaskViaSingleThreadTaskRunner) {
#if defined(OS_WIN) #if defined(OS_WIN)
TEST_F(BrowserThreadTest, PostTaskViaCOMSTATaskRunner) { TEST_F(BrowserThreadTest, PostTaskViaCOMSTATaskRunner) {
scoped_refptr<base::SingleThreadTaskRunner> task_runner = scoped_refptr<base::SingleThreadTaskRunner> task_runner =
base::CreateCOMSTATaskRunner({BrowserThread::UI}); GetUIThreadTaskRunner({});
base::RunLoop run_loop; base::RunLoop run_loop;
EXPECT_TRUE(task_runner->PostTask( EXPECT_TRUE(task_runner->PostTask(
FROM_HERE, base::BindOnce(&BasicFunction, run_loop.QuitWhenIdleClosure(), FROM_HERE, base::BindOnce(&BasicFunction, run_loop.QuitWhenIdleClosure(),
...@@ -266,7 +264,7 @@ TEST_F(BrowserThreadTest, PostTaskViaCOMSTATaskRunner) { ...@@ -266,7 +264,7 @@ TEST_F(BrowserThreadTest, PostTaskViaCOMSTATaskRunner) {
TEST_F(BrowserThreadTest, ReleaseViaTaskRunner) { TEST_F(BrowserThreadTest, ReleaseViaTaskRunner) {
scoped_refptr<base::SingleThreadTaskRunner> task_runner = scoped_refptr<base::SingleThreadTaskRunner> task_runner =
base::CreateSingleThreadTaskRunner({BrowserThread::UI}); GetUIThreadTaskRunner({});
base::RunLoop run_loop; base::RunLoop run_loop;
ExpectRelease(run_loop.QuitWhenIdleClosure()); ExpectRelease(run_loop.QuitWhenIdleClosure());
task_runner->ReleaseSoon(FROM_HERE, base::WrapRefCounted(this)); task_runner->ReleaseSoon(FROM_HERE, base::WrapRefCounted(this));
...@@ -277,9 +275,8 @@ TEST_F(BrowserThreadTest, PostTaskAndReply) { ...@@ -277,9 +275,8 @@ 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.
base::RunLoop run_loop; base::RunLoop run_loop;
ASSERT_TRUE(base::PostTaskAndReply(FROM_HERE, {BrowserThread::IO}, ASSERT_TRUE(GetIOThreadTaskRunner({})->PostTaskAndReply(
base::DoNothing(), FROM_HERE, base::DoNothing(), run_loop.QuitWhenIdleClosure()));
run_loop.QuitWhenIdleClosure()));
run_loop.Run(); run_loop.Run();
} }
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "base/no_destructor.h" #include "base/no_destructor.h"
#include "base/run_loop.h" #include "base/run_loop.h"
#include "base/task/post_task.h" #include "base/task/post_task.h"
#include "base/task/task_traits_extension.h"
#include "base/threading/thread_task_runner_handle.h" #include "base/threading/thread_task_runner_handle.h"
#include "base/trace_event/trace_event.h" #include "base/trace_event/trace_event.h"
#include "build/build_config.h" #include "build/build_config.h"
...@@ -24,47 +25,27 @@ ...@@ -24,47 +25,27 @@
#include "base/android/task_scheduler/post_task_android.h" #include "base/android/task_scheduler/post_task_android.h"
#endif #endif
using QueueType = content::BrowserTaskQueues::QueueType;
namespace content { namespace content {
namespace { namespace {
using QueueType = ::content::BrowserTaskQueues::QueueType; // Returns the BrowserThread::ID stored in |traits| which must be coming from a
// call through BaseBrowserTaskExecutor and hence have the
// BrowserTaskTraitsExtension.
BrowserThread::ID ExtractBrowserThreadId(const base::TaskTraits& traits) {
DCHECK_EQ(BrowserTaskTraitsExtension::kExtensionId, traits.extension_id());
const BrowserTaskTraitsExtension extension =
traits.GetExtension<BrowserTaskTraitsExtension>();
const BrowserThread::ID thread_id = extension.browser_thread();
DCHECK_GE(thread_id, 0);
return thread_id;
}
// |g_browser_task_executor| is intentionally leaked on shutdown. // |g_browser_task_executor| is intentionally leaked on shutdown.
BrowserTaskExecutor* g_browser_task_executor = nullptr; BrowserTaskExecutor* g_browser_task_executor = nullptr;
QueueType GetQueueType(const base::TaskTraits& traits,
BrowserTaskType task_type) {
switch (task_type) {
case BrowserTaskType::kBootstrap:
// Note we currently ignore the priority for bootstrap tasks.
return QueueType::kBootstrap;
case BrowserTaskType::kNavigation:
case BrowserTaskType::kPreconnect:
// Note we currently ignore the priority for navigation and preconnection
// tasks.
return QueueType::kNavigationAndPreconnection;
case BrowserTaskType::kDefault:
// Defer to traits.priority() below.
break;
case BrowserTaskType::kBrowserTaskType_Last:
NOTREACHED();
}
switch (traits.priority()) {
case base::TaskPriority::BEST_EFFORT:
return QueueType::kBestEffort;
case base::TaskPriority::USER_VISIBLE:
return QueueType::kUserVisible;
case base::TaskPriority::USER_BLOCKING:
return QueueType::kUserBlocking;
}
}
} // namespace } // namespace
BaseBrowserTaskExecutor::BaseBrowserTaskExecutor() = default; BaseBrowserTaskExecutor::BaseBrowserTaskExecutor() = default;
...@@ -77,30 +58,30 @@ bool BaseBrowserTaskExecutor::PostDelayedTask(const base::Location& from_here, ...@@ -77,30 +58,30 @@ bool BaseBrowserTaskExecutor::PostDelayedTask(const base::Location& from_here,
base::TimeDelta delay) { base::TimeDelta delay) {
if (traits.extension_id() != BrowserTaskTraitsExtension::kExtensionId || if (traits.extension_id() != BrowserTaskTraitsExtension::kExtensionId ||
traits.GetExtension<BrowserTaskTraitsExtension>().nestable()) { traits.GetExtension<BrowserTaskTraitsExtension>().nestable()) {
return GetTaskRunner(traits)->PostDelayedTask(from_here, std::move(task), return GetTaskRunner(ExtractBrowserThreadId(traits), traits)
delay); ->PostDelayedTask(from_here, std::move(task), delay);
} else { } else {
return GetTaskRunner(traits)->PostNonNestableDelayedTask( return GetTaskRunner(ExtractBrowserThreadId(traits), traits)
from_here, std::move(task), delay); ->PostNonNestableDelayedTask(from_here, std::move(task), delay);
} }
} }
scoped_refptr<base::TaskRunner> BaseBrowserTaskExecutor::CreateTaskRunner( scoped_refptr<base::TaskRunner> BaseBrowserTaskExecutor::CreateTaskRunner(
const base::TaskTraits& traits) { const base::TaskTraits& traits) {
return GetTaskRunner(traits); return GetTaskRunner(ExtractBrowserThreadId(traits), traits);
} }
scoped_refptr<base::SequencedTaskRunner> scoped_refptr<base::SequencedTaskRunner>
BaseBrowserTaskExecutor::CreateSequencedTaskRunner( BaseBrowserTaskExecutor::CreateSequencedTaskRunner(
const base::TaskTraits& traits) { const base::TaskTraits& traits) {
return GetTaskRunner(traits); return GetTaskRunner(ExtractBrowserThreadId(traits), traits);
} }
scoped_refptr<base::SingleThreadTaskRunner> scoped_refptr<base::SingleThreadTaskRunner>
BaseBrowserTaskExecutor::CreateSingleThreadTaskRunner( BaseBrowserTaskExecutor::CreateSingleThreadTaskRunner(
const base::TaskTraits& traits, const base::TaskTraits& traits,
base::SingleThreadTaskRunnerThreadMode thread_mode) { base::SingleThreadTaskRunnerThreadMode thread_mode) {
return GetTaskRunner(traits); return GetTaskRunner(ExtractBrowserThreadId(traits), traits);
} }
#if defined(OS_WIN) #if defined(OS_WIN)
...@@ -108,42 +89,71 @@ scoped_refptr<base::SingleThreadTaskRunner> ...@@ -108,42 +89,71 @@ scoped_refptr<base::SingleThreadTaskRunner>
BaseBrowserTaskExecutor::CreateCOMSTATaskRunner( BaseBrowserTaskExecutor::CreateCOMSTATaskRunner(
const base::TaskTraits& traits, const base::TaskTraits& traits,
base::SingleThreadTaskRunnerThreadMode thread_mode) { base::SingleThreadTaskRunnerThreadMode thread_mode) {
return GetTaskRunner(traits); return GetTaskRunner(ExtractBrowserThreadId(traits), traits);
} }
#endif // defined(OS_WIN) #endif // defined(OS_WIN)
scoped_refptr<base::SingleThreadTaskRunner> scoped_refptr<base::SingleThreadTaskRunner>
BaseBrowserTaskExecutor::GetTaskRunner(const base::TaskTraits& traits) const { BaseBrowserTaskExecutor::GetTaskRunner(BrowserThread::ID identifier,
auto id_and_queue = GetThreadIdAndQueueType(traits); const base::TaskTraits& traits) const {
DCHECK(traits.extension_id() ==
base::TaskTraitsExtensionStorage::kInvalidExtensionId ||
ExtractBrowserThreadId(traits) == identifier);
const QueueType queue_type = GetQueueType(traits);
switch (id_and_queue.thread_id) { switch (identifier) {
case BrowserThread::UI: { case BrowserThread::UI: {
return browser_ui_thread_handle_->GetBrowserTaskRunner( return browser_ui_thread_handle_->GetBrowserTaskRunner(queue_type);
id_and_queue.queue_type);
} }
case BrowserThread::IO: case BrowserThread::IO:
return browser_io_thread_handle_->GetBrowserTaskRunner( return browser_io_thread_handle_->GetBrowserTaskRunner(queue_type);
id_and_queue.queue_type);
case BrowserThread::ID_COUNT: case BrowserThread::ID_COUNT:
NOTREACHED(); NOTREACHED();
} }
return nullptr; return nullptr;
} }
BaseBrowserTaskExecutor::ThreadIdAndQueueType // static
BaseBrowserTaskExecutor::GetThreadIdAndQueueType( QueueType BaseBrowserTaskExecutor::GetQueueType(
const base::TaskTraits& traits) const { const base::TaskTraits& traits) {
DCHECK_EQ(BrowserTaskTraitsExtension::kExtensionId, traits.extension_id()); if (traits.extension_id() == BrowserTaskTraitsExtension::kExtensionId) {
const BrowserTaskTraitsExtension extension = const BrowserTaskTraitsExtension extension =
traits.GetExtension<BrowserTaskTraitsExtension>(); traits.GetExtension<BrowserTaskTraitsExtension>();
const BrowserTaskType task_type = extension.task_type();
DCHECK_LT(task_type, BrowserTaskType::kBrowserTaskType_Last);
switch (task_type) {
case BrowserTaskType::kBootstrap:
// Note we currently ignore the priority for bootstrap tasks.
return QueueType::kBootstrap;
case BrowserTaskType::kNavigation:
case BrowserTaskType::kPreconnect:
// Note we currently ignore the priority for navigation and
// preconnection tasks.
return QueueType::kNavigationAndPreconnection;
case BrowserTaskType::kDefault:
// Defer to traits.priority() below.
break;
case BrowserTaskType::kBrowserTaskType_Last:
NOTREACHED();
}
}
const BrowserThread::ID thread_id = extension.browser_thread(); switch (traits.priority()) {
DCHECK_GE(thread_id, 0); case base::TaskPriority::BEST_EFFORT:
return QueueType::kBestEffort;
const BrowserTaskType task_type = extension.task_type(); case base::TaskPriority::USER_VISIBLE:
DCHECK_LT(task_type, BrowserTaskType::kBrowserTaskType_Last); return QueueType::kUserVisible;
return {thread_id, GetQueueType(traits, task_type)}; case base::TaskPriority::USER_BLOCKING:
return QueueType::kUserBlocking;
}
} }
BrowserTaskExecutor::BrowserTaskExecutor( BrowserTaskExecutor::BrowserTaskExecutor(
...@@ -282,6 +292,20 @@ void BrowserTaskExecutor::EnableAllQueues() { ...@@ -282,6 +292,20 @@ void BrowserTaskExecutor::EnableAllQueues() {
g_browser_task_executor->browser_io_thread_handle_->EnableAllQueues(); g_browser_task_executor->browser_io_thread_handle_->EnableAllQueues();
} }
// static
scoped_refptr<base::SingleThreadTaskRunner>
BrowserTaskExecutor::GetUIThreadTaskRunner(const BrowserTaskTraits& traits) {
DCHECK(g_browser_task_executor);
return g_browser_task_executor->GetTaskRunner(BrowserThread::UI, traits);
}
// static
scoped_refptr<base::SingleThreadTaskRunner>
BrowserTaskExecutor::GetIOThreadTaskRunner(const BrowserTaskTraits& traits) {
DCHECK(g_browser_task_executor);
return g_browser_task_executor->GetTaskRunner(BrowserThread::IO, traits);
}
// static // static
void BrowserTaskExecutor::InitializeIOThread() { void BrowserTaskExecutor::InitializeIOThread() {
DCHECK(g_browser_task_executor); DCHECK(g_browser_task_executor);
......
...@@ -58,20 +58,25 @@ class CONTENT_EXPORT BaseBrowserTaskExecutor : public base::TaskExecutor { ...@@ -58,20 +58,25 @@ class CONTENT_EXPORT BaseBrowserTaskExecutor : public base::TaskExecutor {
base::SingleThreadTaskRunnerThreadMode thread_mode) override; base::SingleThreadTaskRunnerThreadMode thread_mode) override;
#endif // defined(OS_WIN) #endif // defined(OS_WIN)
struct ThreadIdAndQueueType { // Returns the task runner for |traits| under |identifier|. Note: during the
BrowserThread::ID thread_id; // migration away from task traits extension, |traits| may also contain a
BrowserTaskQueues::QueueType queue_type; // browser thread id, if so, it should match |identifier| (|identifier| has to
}; // be provided explicitly because in the new source of tasks it's not part of
// |traits|) -- ref. crbug.com/1026641.
ThreadIdAndQueueType GetThreadIdAndQueueType( scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner(
BrowserThread::ID identifier,
const base::TaskTraits& traits) const; const base::TaskTraits& traits) const;
// Helper to match a QueueType from TaskTraits.
// TODO(1026641): Take BrowserTaskTraits as a parameter when getting off the
// need to support base::TaskTraits currently passed to this class in its role
// as a base::TaskExecutor.
static content::BrowserTaskQueues::QueueType GetQueueType(
const base::TaskTraits& traits);
protected: protected:
virtual BrowserThread::ID GetCurrentThreadID() const = 0; virtual BrowserThread::ID GetCurrentThreadID() const = 0;
scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunner(
const base::TaskTraits& traits) const;
scoped_refptr<BrowserUIThreadScheduler::Handle> browser_ui_thread_handle_; scoped_refptr<BrowserUIThreadScheduler::Handle> browser_ui_thread_handle_;
scoped_refptr<BrowserIOThreadDelegate::Handle> browser_io_thread_handle_; scoped_refptr<BrowserIOThreadDelegate::Handle> browser_io_thread_handle_;
}; };
...@@ -126,6 +131,16 @@ class CONTENT_EXPORT BrowserTaskExecutor : public BaseBrowserTaskExecutor { ...@@ -126,6 +131,16 @@ class CONTENT_EXPORT BrowserTaskExecutor : public BaseBrowserTaskExecutor {
// Can be called multiple times. // Can be called multiple times.
static void EnableAllQueues(); static void EnableAllQueues();
// Helpers to statically call into BaseBrowserTaskExecutor::GetTaskRunner()
// from browser_thread_impl.cc. Callers should use browser_thread.h's
// GetUIThreadTaskRunner over this.
// TODO(1026641): Clean up this indirection after the migration (once
// registering a base::BrowserTaskExecutor is no longer necessary).
static scoped_refptr<base::SingleThreadTaskRunner> GetUIThreadTaskRunner(
const BrowserTaskTraits& traits);
static scoped_refptr<base::SingleThreadTaskRunner> GetIOThreadTaskRunner(
const BrowserTaskTraits& traits);
// As Create but with the user provided objects. Must call // As Create but with the user provided objects. Must call
// BindToUIThreadForTesting before tasks can be run on the UI thread. // BindToUIThreadForTesting before tasks can be run on the UI thread.
static void CreateForTesting( static void CreateForTesting(
......
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
#include "base/bind.h" #include "base/bind.h"
#include "base/bind_helpers.h" #include "base/bind_helpers.h"
#include "base/task/post_task.h"
#include "base/task/task_traits.h" #include "base/task/task_traits.h"
#include "base/task/thread_pool/thread_pool_instance.h" #include "base/task/thread_pool/thread_pool_instance.h"
#include "base/test/bind_test_util.h" #include "base/test/bind_test_util.h"
...@@ -49,15 +48,15 @@ using StrictMockTask = ...@@ -49,15 +48,15 @@ using StrictMockTask =
testing::StrictMock<base::MockCallback<base::RepeatingCallback<void()>>>; testing::StrictMock<base::MockCallback<base::RepeatingCallback<void()>>>;
TEST_F(BrowserTaskExecutorTest, RegisterExecutorForBothThreads) { TEST_F(BrowserTaskExecutorTest, RegisterExecutorForBothThreads) {
base::PostTask(FROM_HERE, {BrowserThread::UI}, base::BindOnce([]() { GetUIThreadTaskRunner({})->PostTask(
EXPECT_THAT(base::GetTaskExecutorForCurrentThread(), FROM_HERE, base::BindOnce([]() {
NotNull()); EXPECT_THAT(base::GetTaskExecutorForCurrentThread(), NotNull());
})); }));
base::PostTask(FROM_HERE, {BrowserThread::IO}, base::BindOnce([]() { GetIOThreadTaskRunner({})->PostTask(
EXPECT_THAT(base::GetTaskExecutorForCurrentThread(), FROM_HERE, base::BindOnce([]() {
NotNull()); EXPECT_THAT(base::GetTaskExecutorForCurrentThread(), NotNull());
})); }));
BrowserTaskExecutor::RunAllPendingTasksOnThreadForTesting(BrowserThread::UI); BrowserTaskExecutor::RunAllPendingTasksOnThreadForTesting(BrowserThread::UI);
BrowserTaskExecutor::RunAllPendingTasksOnThreadForTesting(BrowserThread::IO); BrowserTaskExecutor::RunAllPendingTasksOnThreadForTesting(BrowserThread::IO);
...@@ -70,7 +69,7 @@ TEST_F(BrowserTaskExecutorTest, RunAllPendingTasksForTestingOnUI) { ...@@ -70,7 +69,7 @@ TEST_F(BrowserTaskExecutorTest, RunAllPendingTasksForTestingOnUI) {
base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, task_2.Get()); base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, task_2.Get());
})); }));
base::PostTask(FROM_HERE, {BrowserThread::UI}, task_1.Get()); GetUIThreadTaskRunner({})->PostTask(FROM_HERE, task_1.Get());
BrowserTaskExecutor::RunAllPendingTasksOnThreadForTesting(BrowserThread::UI); BrowserTaskExecutor::RunAllPendingTasksOnThreadForTesting(BrowserThread::UI);
...@@ -84,10 +83,10 @@ TEST_F(BrowserTaskExecutorTest, RunAllPendingTasksForTestingOnIO) { ...@@ -84,10 +83,10 @@ TEST_F(BrowserTaskExecutorTest, RunAllPendingTasksForTestingOnIO) {
StrictMockTask task_1; StrictMockTask task_1;
StrictMockTask task_2; StrictMockTask task_2;
EXPECT_CALL(task_1, Run).WillOnce(testing::Invoke([&]() { EXPECT_CALL(task_1, Run).WillOnce(testing::Invoke([&]() {
base::PostTask(FROM_HERE, {BrowserThread::IO}, task_2.Get()); GetIOThreadTaskRunner({})->PostTask(FROM_HERE, task_2.Get());
})); }));
base::PostTask(FROM_HERE, {BrowserThread::IO}, task_1.Get()); GetIOThreadTaskRunner({})->PostTask(FROM_HERE, task_1.Get());
BrowserTaskExecutor::RunAllPendingTasksOnThreadForTesting(BrowserThread::IO); BrowserTaskExecutor::RunAllPendingTasksOnThreadForTesting(BrowserThread::IO);
...@@ -103,15 +102,15 @@ TEST_F(BrowserTaskExecutorTest, RunAllPendingTasksForTestingOnIOIsReentrant) { ...@@ -103,15 +102,15 @@ TEST_F(BrowserTaskExecutorTest, RunAllPendingTasksForTestingOnIOIsReentrant) {
StrictMockTask task_3; StrictMockTask task_3;
EXPECT_CALL(task_1, Run).WillOnce(Invoke([&]() { EXPECT_CALL(task_1, Run).WillOnce(Invoke([&]() {
base::PostTask(FROM_HERE, {BrowserThread::IO}, task_2.Get()); GetIOThreadTaskRunner({})->PostTask(FROM_HERE, task_2.Get());
BrowserTaskExecutor::RunAllPendingTasksOnThreadForTesting( BrowserTaskExecutor::RunAllPendingTasksOnThreadForTesting(
BrowserThread::IO); BrowserThread::IO);
})); }));
EXPECT_CALL(task_2, Run).WillOnce(Invoke([&]() { EXPECT_CALL(task_2, Run).WillOnce(Invoke([&]() {
base::PostTask(FROM_HERE, {BrowserThread::IO}, task_3.Get()); GetIOThreadTaskRunner({})->PostTask(FROM_HERE, task_3.Get());
})); }));
base::PostTask(FROM_HERE, {BrowserThread::IO}, task_1.Get()); GetIOThreadTaskRunner({})->PostTask(FROM_HERE, task_1.Get());
BrowserTaskExecutor::RunAllPendingTasksOnThreadForTesting(BrowserThread::IO); BrowserTaskExecutor::RunAllPendingTasksOnThreadForTesting(BrowserThread::IO);
// Cleanup pending tasks, as BrowserTaskEnvironment will run them. // Cleanup pending tasks, as BrowserTaskEnvironment will run them.
...@@ -134,44 +133,33 @@ class BrowserTaskTraitsMappingTest : public BrowserTaskExecutorTest { ...@@ -134,44 +133,33 @@ class BrowserTaskTraitsMappingTest : public BrowserTaskExecutorTest {
} }
}; };
template <BrowserThread::ID ID>
void CheckExpectations() {
EXPECT_EQ(GetQueueType({ID, TaskPriority::BEST_EFFORT}),
QueueType::kBestEffort);
EXPECT_EQ(GetQueueType({ID, TaskPriority::USER_VISIBLE}),
QueueType::kUserVisible);
EXPECT_EQ(GetQueueType({ID, TaskPriority::USER_BLOCKING}),
QueueType::kUserBlocking);
EXPECT_EQ(GetQueueType({ID, BrowserTaskType::kBootstrap}),
QueueType::kBootstrap);
EXPECT_EQ(GetQueueType({ID, BrowserTaskType::kDefault}),
QueueType::kUserBlocking);
EXPECT_EQ(GetQueueType({ID, BrowserTaskType::kNavigation}),
QueueType::kNavigationAndPreconnection);
EXPECT_EQ(GetQueueType({ID, BrowserTaskType::kPreconnect}),
QueueType::kNavigationAndPreconnection);
EXPECT_EQ(GetQueueType({ID}), QueueType::kUserBlocking);
}
private: private:
QueueType GetQueueType(const base::TaskTraits& traits) {
return test_executor_.GetThreadIdAndQueueType(traits).queue_type;
}
TestExecutor test_executor_; TestExecutor test_executor_;
}; };
TEST_F(BrowserTaskTraitsMappingTest, BrowserTaskTraitsMapToProperPriorities) { TEST_F(BrowserTaskTraitsMappingTest, BrowserTaskTraitsMapToProperPriorities) {
CheckExpectations<BrowserThread::UI>(); EXPECT_EQ(BrowserTaskExecutor::GetQueueType({TaskPriority::BEST_EFFORT}),
CheckExpectations<BrowserThread::IO>(); QueueType::kBestEffort);
EXPECT_EQ(BrowserTaskExecutor::GetQueueType({TaskPriority::USER_VISIBLE}),
QueueType::kUserVisible);
EXPECT_EQ(BrowserTaskExecutor::GetQueueType({TaskPriority::USER_BLOCKING}),
QueueType::kUserBlocking);
EXPECT_EQ(BrowserTaskExecutor::GetQueueType({BrowserTaskType::kBootstrap}),
QueueType::kBootstrap);
EXPECT_EQ(BrowserTaskExecutor::GetQueueType({BrowserTaskType::kDefault}),
QueueType::kUserBlocking);
EXPECT_EQ(BrowserTaskExecutor::GetQueueType({BrowserTaskType::kNavigation}),
QueueType::kNavigationAndPreconnection);
EXPECT_EQ(BrowserTaskExecutor::GetQueueType({BrowserTaskType::kPreconnect}),
QueueType::kNavigationAndPreconnection);
EXPECT_EQ(BrowserTaskExecutor::GetQueueType({}), QueueType::kUserBlocking);
} }
TEST_F(BrowserTaskTraitsMappingTest, TEST_F(BrowserTaskTraitsMappingTest,
UIThreadTaskRunnerHasSamePriorityAsUIBlocking) { UIThreadTaskRunnerHasSamePriorityAsUIBlocking) {
auto ui_blocking = base::CreateSingleThreadTaskRunner( auto ui_blocking = GetUIThreadTaskRunner({TaskPriority::USER_BLOCKING});
{BrowserThread::UI, TaskPriority::USER_BLOCKING});
auto thread_task_runner = base::ThreadTaskRunnerHandle::Get(); auto thread_task_runner = base::ThreadTaskRunnerHandle::Get();
std::vector<int> order; std::vector<int> order;
...@@ -213,8 +201,6 @@ class BrowserTaskExecutorWithCustomSchedulerTest : public testing::Test { ...@@ -213,8 +201,6 @@ class BrowserTaskExecutorWithCustomSchedulerTest : public testing::Test {
}; };
public: public:
using QueueType = BrowserTaskQueues::QueueType;
~BrowserTaskExecutorWithCustomSchedulerTest() override { ~BrowserTaskExecutorWithCustomSchedulerTest() override {
BrowserTaskExecutor::ResetForTesting(); BrowserTaskExecutor::ResetForTesting();
} }
...@@ -229,14 +215,17 @@ TEST_F(BrowserTaskExecutorWithCustomSchedulerTest, ...@@ -229,14 +215,17 @@ TEST_F(BrowserTaskExecutorWithCustomSchedulerTest,
StrictMockTask user_visible; StrictMockTask user_visible;
StrictMockTask user_blocking; StrictMockTask user_blocking;
base::PostTask(FROM_HERE, GetUIThreadTaskRunner({base::TaskPriority::BEST_EFFORT})
{BrowserThread::UI, base::TaskPriority::BEST_EFFORT}, ->PostTask(FROM_HERE,
best_effort.Get()); best_effort.Get());
base::PostTask(FROM_HERE, GetUIThreadTaskRunner({base::TaskPriority::USER_VISIBLE})
{BrowserThread::UI, base::TaskPriority::USER_VISIBLE}, ->PostTask(FROM_HERE,
user_visible.Get()); user_visible.Get());
base::PostTask(FROM_HERE, GetUIThreadTaskRunner({base::TaskPriority::USER_BLOCKING})
{BrowserThread::UI, base::TaskPriority::USER_BLOCKING}, ->PostTask(FROM_HERE,
user_blocking.Get()); user_blocking.Get());
EXPECT_CALL(user_visible, Run); EXPECT_CALL(user_visible, Run);
...@@ -247,19 +236,20 @@ TEST_F(BrowserTaskExecutorWithCustomSchedulerTest, ...@@ -247,19 +236,20 @@ TEST_F(BrowserTaskExecutorWithCustomSchedulerTest,
TEST_F(BrowserTaskExecutorWithCustomSchedulerTest, TEST_F(BrowserTaskExecutorWithCustomSchedulerTest,
BestEffortTasksRunAfterStartup) { BestEffortTasksRunAfterStartup) {
auto ui_best_effort_runner = base::CreateSingleThreadTaskRunner( auto ui_best_effort_runner =
{BrowserThread::UI, base::TaskPriority::BEST_EFFORT}); GetUIThreadTaskRunner({base::TaskPriority::BEST_EFFORT});
StrictMockTask best_effort; StrictMockTask best_effort;
ui_best_effort_runner->PostTask(FROM_HERE, best_effort.Get()); ui_best_effort_runner->PostTask(FROM_HERE, best_effort.Get());
ui_best_effort_runner->PostDelayedTask( ui_best_effort_runner->PostDelayedTask(
FROM_HERE, best_effort.Get(), base::TimeDelta::FromMilliseconds(100)); FROM_HERE, best_effort.Get(), base::TimeDelta::FromMilliseconds(100));
base::PostDelayedTask( GetUIThreadTaskRunner({base::TaskPriority::BEST_EFFORT})
FROM_HERE, {BrowserThread::UI, base::TaskPriority::BEST_EFFORT}, ->PostDelayedTask(FROM_HERE, best_effort.Get(),
best_effort.Get(), base::TimeDelta::FromMilliseconds(100)); base::TimeDelta::FromMilliseconds(100));
base::PostTask(FROM_HERE, GetUIThreadTaskRunner({base::TaskPriority::BEST_EFFORT})
{BrowserThread::UI, base::TaskPriority::BEST_EFFORT}, ->PostTask(FROM_HERE,
best_effort.Get()); best_effort.Get());
task_environment_.RunUntilIdle(); task_environment_.RunUntilIdle();
......
...@@ -80,7 +80,8 @@ class CONTENT_EXPORT BrowserTaskTraitsExtension { ...@@ -80,7 +80,8 @@ class CONTENT_EXPORT BrowserTaskTraitsExtension {
base::trait_helpers::AreValidTraits<ValidTrait, ArgTypes...>::value>> base::trait_helpers::AreValidTraits<ValidTrait, ArgTypes...>::value>>
constexpr BrowserTaskTraitsExtension(ArgTypes... args) constexpr BrowserTaskTraitsExtension(ArgTypes... args)
: browser_thread_( : browser_thread_(
base::trait_helpers::GetEnum<BrowserThread::ID>(args...)), base::trait_helpers::GetEnum<BrowserThread::ID,
BrowserThread::ID_COUNT>(args...)),
task_type_( task_type_(
base::trait_helpers::GetEnum<BrowserTaskType, base::trait_helpers::GetEnum<BrowserTaskType,
BrowserTaskType::kDefault>(args...)), BrowserTaskType::kDefault>(args...)),
...@@ -105,7 +106,13 @@ class CONTENT_EXPORT BrowserTaskTraitsExtension { ...@@ -105,7 +106,13 @@ class CONTENT_EXPORT BrowserTaskTraitsExtension {
static_cast<bool>(extension.data[2])); static_cast<bool>(extension.data[2]));
} }
constexpr BrowserThread::ID browser_thread() const { return browser_thread_; } constexpr BrowserThread::ID browser_thread() const {
// TODO(1026641): Migrate to BrowserTaskTraits under which BrowserThread is
// not a trait. Until then, only code that knows traits have explicitly set
// the BrowserThread trait should check this field.
DCHECK_NE(browser_thread_, BrowserThread::ID_COUNT);
return browser_thread_;
}
constexpr BrowserTaskType task_type() const { return task_type_; } constexpr BrowserTaskType task_type() const { return task_type_; }
...@@ -135,6 +142,40 @@ constexpr base::TaskTraitsExtensionStorage MakeTaskTraitsExtension( ...@@ -135,6 +142,40 @@ constexpr base::TaskTraitsExtensionStorage MakeTaskTraitsExtension(
.Serialize(); .Serialize();
} }
class CONTENT_EXPORT BrowserTaskTraits : public base::TaskTraits {
public:
struct ValidTrait : public base::TaskTraits::ValidTrait {
ValidTrait(BrowserTaskType);
ValidTrait(NonNestable);
// TODO(1026641): Reconsider whether BrowserTaskTraits should really be
// supporting base::TaskPriority.
ValidTrait(base::TaskPriority);
};
// TODO(1026641): Get rid of BrowserTaskTraitsExtension and store its members
// (|task_type_| & |nestable_|) directly in BrowserTaskTraits.
template <
class... ArgTypes,
class CheckArgumentsAreValid = std::enable_if_t<
base::trait_helpers::AreValidTraits<ValidTrait, ArgTypes...>::value>>
constexpr BrowserTaskTraits(ArgTypes... args) : base::TaskTraits(args...) {}
BrowserTaskType task_type() {
return GetExtension<BrowserTaskTraitsExtension>().task_type();
}
// Returns true if tasks with these traits may run in a nested RunLoop.
bool nestable() const {
return GetExtension<BrowserTaskTraitsExtension>().nestable();
}
};
static_assert(sizeof(BrowserTaskTraits) == sizeof(base::TaskTraits),
"During the migration away from BrowserTasktraitsExtension, "
"BrowserTaskTraits must only use base::TaskTraits for storage "
"to prevent slicing.");
} // namespace content } // namespace content
#endif // CONTENT_PUBLIC_BROWSER_BROWSER_TASK_TRAITS_H_ #endif // CONTENT_PUBLIC_BROWSER_BROWSER_TASK_TRAITS_H_
...@@ -14,11 +14,9 @@ namespace content { ...@@ -14,11 +14,9 @@ namespace content {
#if defined(NCTEST_BROWSER_TASK_TRAITS_MULTIPLE_THREADS) // [r"The traits bag contains multiple traits of the same type."] #if defined(NCTEST_BROWSER_TASK_TRAITS_MULTIPLE_THREADS) // [r"The traits bag contains multiple traits of the same type."]
constexpr base::TaskTraits traits = {BrowserThread::UI, constexpr base::TaskTraits traits = {BrowserThread::UI,
BrowserThread::IO}; BrowserThread::IO};
#elif defined(NCTEST_BROWSER_TASK_TRAITS_MULTIPLE_TASK_TYPES) // [r"The traits bag is missing a required trait."] #elif defined(NCTEST_BROWSER_TASK_TRAITS_MULTIPLE_TASK_TYPES) // [r"The traits bag contains multiple traits of the same type."]
constexpr base::TaskTraits traits = {BrowserTaskType::kNavigation, constexpr base::TaskTraits traits = {BrowserTaskType::kNavigation,
BrowserTaskType::kBootstrap}; BrowserTaskType::kBootstrap};
#elif defined(NCTEST_BROWSER_TASK_TRAITS_NO_THREAD_ID) // [r"The traits bag is missing a required trait."]
constexpr base::TaskTraits traits = {BrowserTaskType::kNavigation};
#endif #endif
......
...@@ -21,6 +21,11 @@ ...@@ -21,6 +21,11 @@
namespace content { namespace content {
// TODO(1026641): Include browser_task_traits.h directly when the migration to
// Get(UI|IO)ThreadTaskrunner() is complete and the cyclic dependency of
// browser_task_traits.h on BrowserThread::ID is broken.
class BrowserTaskTraits;
class BrowserThreadImpl; class BrowserThreadImpl;
// Use DCHECK_CURRENTLY_ON(BrowserThread::ID) to assert that a function can only // Use DCHECK_CURRENTLY_ON(BrowserThread::ID) to assert that a function can only
...@@ -30,34 +35,45 @@ class BrowserThreadImpl; ...@@ -30,34 +35,45 @@ class BrowserThreadImpl;
<< ::content::BrowserThread::GetDCheckCurrentlyOnErrorMessage( \ << ::content::BrowserThread::GetDCheckCurrentlyOnErrorMessage( \
thread_identifier)) thread_identifier))
/////////////////////////////////////////////////////////////////////////////// // The main entry point to post tasks to the UI thread. Tasks posted with the
// BrowserThread // same |traits| will run in posting order (i.e. according to the
// SequencedTaskRunner contract). Tasks posted with different |traits| can be
// re-ordered. You may keep a reference to this task runner, it's always
// thread-safe to post to it though it may start returning false at some point
// during shutdown when it definitely is no longer accepting tasks.
// //
// Utility functions for threads that are known by a browser-wide name. For // In unit tests, there must be a content::BrowserTaskEnvironment in scope for
// example, there is one IO thread for the entire browser process, and various // this API to be available.
// pieces of code find it useful to retrieve a pointer to the IO thread's
// message loop.
// //
// See browser_task_traits.h for posting Tasks to a BrowserThread. // TODO(1026641): Make default traits |{}| the default param when it's possible
// to include browser_task_traits.h in this file (see note above on the
// BrowserTaskTraits fwd-decl).
CONTENT_EXPORT scoped_refptr<base::SingleThreadTaskRunner>
GetUIThreadTaskRunner(const BrowserTaskTraits& traits);
// The BrowserThread::IO counterpart to GetUIThreadTaskRunner().
CONTENT_EXPORT scoped_refptr<base::SingleThreadTaskRunner>
GetIOThreadTaskRunner(const BrowserTaskTraits& traits);
///////////////////////////////////////////////////////////////////////////////
// BrowserThread
// //
// This class automatically handles the lifetime of different threads. You // Utility functions for threads that are known by a browser-wide name.
// 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.
// NOTE: threads must be listed in the order of their life-time, with each
// thread outliving every other thread below it.
enum ID { enum ID {
// The main thread in the browser. // The main thread in the browser. It stops running tasks during shutdown
// and is never joined.
UI, UI,
// This is the thread that processes non-blocking IO, i.e. IPC and network. // This is the thread that processes non-blocking I/O, i.e. IPC and network.
// Blocking I/O should happen in ThreadPool. // Blocking I/O should happen in base::ThreadPool. It is joined on shutdown
// (and thus any task posted to it may block shutdown).
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*TaskRunner to run tasks on the ThreadPool. // base::ThreadPool::Create*TaskRunner to run tasks on the base::ThreadPool.
// 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
...@@ -65,15 +81,12 @@ class CONTENT_EXPORT BrowserThread { ...@@ -65,15 +81,12 @@ class CONTENT_EXPORT BrowserThread {
ID_COUNT ID_COUNT
}; };
// NOTE: Task posting APIs have moved to post_task.h. See
// browser_task_traits.h.
// Delete/ReleaseSoon() helpers allow future deletion of an owned object on // Delete/ReleaseSoon() helpers allow future deletion of an owned object on
// its associated thread. If you already have a task runner bound to a // its associated thread. If you already have a task runner bound to a
// BrowserThread you should use its SequencedTaskRunner::DeleteSoon() member // BrowserThread you should use its SequencedTaskRunner::DeleteSoon() member
// method. If you don't, the helpers below avoid having to do // method.
// base::CreateSingleThreadTaskRunner({BrowserThread::ID})->DeleteSoon(...) // TODO(1026641): Get rid of the last few callers to these in favor of an
// which is equivalent. // explicit call to content::GetUIThreadTaskRunner({})->DeleteSoon(...).
template <class T> template <class T>
static bool DeleteSoon(ID identifier, static bool DeleteSoon(ID identifier,
...@@ -98,7 +111,7 @@ class CONTENT_EXPORT BrowserThread { ...@@ -98,7 +111,7 @@ class CONTENT_EXPORT BrowserThread {
} }
// Posts a |task| to run at BEST_EFFORT priority using an arbitrary // Posts a |task| to run at BEST_EFFORT priority using an arbitrary
// |task_runner| for which we do not control the priority // |task_runner| for which we do not control the priority.
// //
// This is useful when a task needs to run on |task_runner| (for thread-safety // This is useful when a task needs to run on |task_runner| (for thread-safety
// reasons) but should be delayed until after critical phases (e.g. startup). // reasons) but should be delayed until after critical phases (e.g. startup).
...@@ -196,8 +209,8 @@ class CONTENT_EXPORT BrowserThread { ...@@ -196,8 +209,8 @@ class CONTENT_EXPORT BrowserThread {
private: private:
friend class BrowserThreadImpl; friend class BrowserThreadImpl;
BrowserThread() = default;
BrowserThread() {}
DISALLOW_COPY_AND_ASSIGN(BrowserThread); DISALLOW_COPY_AND_ASSIGN(BrowserThread);
}; };
......
...@@ -109,7 +109,8 @@ Every Chrome process has ...@@ -109,7 +109,8 @@ Every Chrome process has
* in the browser process (BrowserThread::UI): updates the UI * in the browser process (BrowserThread::UI): updates the UI
* in renderer processes (Blink main thread): runs most of Blink * in renderer processes (Blink main thread): runs most of Blink
* an IO thread * an IO thread
* in the browser process (BrowserThread::IO): handles IPCs and network requests * in the browser process (BrowserThread::IO): handles IPCs and network
requests
* in renderer processes: handles IPCs * in renderer processes: handles IPCs
* a few more special-purpose threads * a few more special-purpose threads
* and a pool of general-purpose threads * and a pool of general-purpose threads
...@@ -222,8 +223,8 @@ class A { ...@@ -222,8 +223,8 @@ class A {
``` ```
Unless a test needs to control precisely how tasks are executed, it is preferred Unless a test needs to control precisely how tasks are executed, it is preferred
to call `base::ThreadPool::PostTask*()` directly (ref. [Testing](#Testing) for less invasive to call `base::ThreadPool::PostTask*()` directly (ref. [Testing](#Testing) for
ways of controlling tasks in tests). less invasive ways of controlling tasks in tests).
## Posting a Sequenced Task ## Posting a Sequenced Task
...@@ -336,10 +337,17 @@ posting order. ...@@ -336,10 +337,17 @@ posting order.
### Posting to the Main Thread or to the IO Thread in the Browser Process ### Posting to the Main Thread or to the IO Thread in the Browser Process
To post tasks to the main thread or to the IO thread, use To post tasks to the main thread or to the IO thread, use
`base::PostTask()` or get the appropriate SingleThreadTaskRunner using `content::GetUIThreadTaskRunner({})` or `content::GetUIThreadTaskRunner({})`
`base::CreateSingleThreadTaskRunner`, supplying a `BrowserThread::ID` from
as trait. For this, you'll also need to include [`content/public/browser/browser_thread.h`](https://cs.chromium.org/chromium/src/content/public/browser/browser_thread.h)
[`content/public/browser/browser_task_traits.h`](https://cs.chromium.org/chromium/src/content/public/browser/browser_task_traits.h).
You may provide additional BrowserTaskTraits as a parameter to those methods
though this is generally still uncommon in BrowserThreads and should be reserved
for advanced use cases.
There's an ongoing migration ([task APIs v3]) away from the previous
base-API-with-traits which you may still find throughout the codebase (it's
equivalent):
```cpp ```cpp
base::PostTask(FROM_HERE, {content::BrowserThread::UI}, ...); base::PostTask(FROM_HERE, {content::BrowserThread::UI}, ...);
...@@ -348,8 +356,10 @@ base::CreateSingleThreadTaskRunner({content::BrowserThread::IO}) ...@@ -348,8 +356,10 @@ base::CreateSingleThreadTaskRunner({content::BrowserThread::IO})
->PostTask(FROM_HERE, ...); ->PostTask(FROM_HERE, ...);
``` ```
Note: This API will soon be updated to follow the API-as-a-destination design Note: For the duration of the migration, you'll unfortunately need to continue
for [task APIs v3], stay tuned! manually including
[`content/public/browser/browser_task_traits.h`](https://cs.chromium.org/chromium/src/content/public/browser/browser_task_traits.h).
to use the browser_thread.h API.
The main thread and the IO thread are already super busy. Therefore, prefer The main thread and the IO thread are already super busy. Therefore, prefer
posting to a general purpose thread when possible (ref. posting to a general purpose thread when possible (ref.
...@@ -362,13 +372,14 @@ Note: It is not necessary to have an explicit post task to the IO thread to ...@@ -362,13 +372,14 @@ Note: It is not necessary to have an explicit post task to the IO thread to
send/receive an IPC or send/receive data on the network. send/receive an IPC or send/receive data on the network.
### Posting to the Main Thread in a Renderer Process ### Posting to the Main Thread in a Renderer Process
TODO TODO(blink-dev)
### Posting to a Custom SingleThreadTaskRunner ### Posting to a Custom SingleThreadTaskRunner
If multiple tasks need to run on the same thread and that thread doesn’t have to If multiple tasks need to run on the same thread and that thread doesn’t have to
be the main thread or the IO thread, post them to a be the main thread or the IO thread, post them to a
`base::SingleThreadTaskRunner` created by `base::Threadpool::CreateSingleThreadTaskRunner`. `base::SingleThreadTaskRunner` created by
`base::Threadpool::CreateSingleThreadTaskRunner`.
```cpp ```cpp
scoped_refptr<SingleThreadTaskRunner> single_thread_task_runner = scoped_refptr<SingleThreadTaskRunner> single_thread_task_runner =
...@@ -387,13 +398,14 @@ be necessary. ...@@ -387,13 +398,14 @@ be necessary.
*** note *** note
**IMPORTANT:** To post a task that needs mutual exclusion with the current **IMPORTANT:** To post a task that needs mutual exclusion with the current
sequence of tasks but doesn’t absolutely need to run on the current physical thread, sequence of tasks but doesn’t absolutely need to run on the current physical
use `base::SequencedTaskRunnerHandle::Get()` instead of thread, use `base::SequencedTaskRunnerHandle::Get()` instead of
`base::ThreadTaskRunnerHandle::Get()` (ref. [Posting to the Current `base::ThreadTaskRunnerHandle::Get()` (ref. [Posting to the Current
Sequence](#Posting-to-the-Current-Virtual_Thread)). That will better document the Sequence](#Posting-to-the-Current-Virtual_Thread)). That will better document
requirements of the posted task and will avoid unnecessarily making your API the requirements of the posted task and will avoid unnecessarily making your API
physical thread-affine. In a single-thread task, `base::SequencedTaskRunnerHandle::Get()` physical thread-affine. In a single-thread task,
is equivalent to `base::ThreadTaskRunnerHandle::Get()`. `base::SequencedTaskRunnerHandle::Get()` is equivalent to
`base::ThreadTaskRunnerHandle::Get()`.
*** ***
If you must post a task to the current physical thread nonetheless, use If you must post a task to the current physical thread nonetheless, use
...@@ -481,11 +493,6 @@ base::ThreadPool::PostTask( ...@@ -481,11 +493,6 @@ base::ThreadPool::PostTask(
base::ThreadPool::PostTask( base::ThreadPool::PostTask(
FROM_HERE, {base::TaskShutdownBehavior::BLOCK_SHUTDOWN}, FROM_HERE, {base::TaskShutdownBehavior::BLOCK_SHUTDOWN},
base::BindOnce(...)); base::BindOnce(...));
// This task will run on the Browser UI thread.
base::ThreadPool::PostTask(
FROM_HERE, {content::BrowserThread::UI},
base::BindOnce(...));
``` ```
## Keeping the Browser Responsive ## Keeping the Browser Responsive
......
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