Skip to content

Commit

Permalink
[base/task] Introduce base::ThreadPool:: for Task APIs v3.
Browse files Browse the repository at this point in the history
Design doc : https://docs.google.com/document/d/1tssusPykvx3g0gvbvU4HxGyn3MjJlIylnsH13-Tv6s4/edit

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

Bug: 1026641
Change-Id: I11c0633779cd2cfe75e29d3318b953c86e32bbec
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1977964
Commit-Queue: Gabriel Charette <gab@chromium.org>
Reviewed-by: François Doray <fdoray@chromium.org>
Cr-Commit-Position: refs/heads/master@{#735609}
  • Loading branch information
Gabriel Charette authored and Commit Bot committed Jan 27, 2020
1 parent 70031b4 commit 43de5c4
Show file tree
Hide file tree
Showing 10 changed files with 511 additions and 88 deletions.
2 changes: 2 additions & 0 deletions base/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,8 @@ jumbo_component("base") {
"task/task_traits.cc",
"task/task_traits.h",
"task/task_traits_extension.h",
"task/thread_pool.cc",
"task/thread_pool.h",
"task/thread_pool/delayed_task_manager.cc",
"task/thread_pool/delayed_task_manager.h",
"task/thread_pool/environment_config.cc",
Expand Down
29 changes: 26 additions & 3 deletions base/task/post_task.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,25 +28,47 @@ namespace base {

// This is the interface to post tasks.
//
// Note: A migration is in-progress away from this API and in favor of explicit
// API-as-a-destination. thread_pool.h is now preferred to the
// base::ThreadPool() to post to the thread pool
//
// To post a simple one-off task with default traits:
// PostTask(FROM_HERE, BindOnce(...));
// modern equivalent:
// ThreadPool::PostTask(FROM_HERE, BindOnce(...));
//
// To post a high priority one-off task to respond to a user interaction:
// PostTask(
// FROM_HERE,
// {ThreadPool(), TaskPriority::USER_BLOCKING},
// BindOnce(...));
// modern equivalent:
// ThreadPool::PostTask(
// FROM_HERE,
// {TaskPriority::USER_BLOCKING},
// BindOnce(...));
//
// To post tasks that must run in sequence with default traits:
// scoped_refptr<SequencedTaskRunner> task_runner =
// CreateSequencedTaskRunner({ThreadPool()});
// task_runner->PostTask(FROM_HERE, BindOnce(...));
// task_runner->PostTask(FROM_HERE, BindOnce(...));
// modern equivalent:
// scoped_refptr<SequencedTaskRunner> task_runner =
// ThreadPool::CreateSequencedTaskRunner({});
// task_runner->PostTask(FROM_HERE, BindOnce(...));
// task_runner->PostTask(FROM_HERE, BindOnce(...));
//
// To post tasks that may block, must run in sequence and can be skipped on
// shutdown:
// scoped_refptr<SequencedTaskRunner> task_runner =
// CreateSequencedTaskRunner(
// CreateSequencedTaskRunner({ThreadPool(), MayBlock(),
// TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
// task_runner->PostTask(FROM_HERE, BindOnce(...));
// task_runner->PostTask(FROM_HERE, BindOnce(...));
// modern equivalent:
// scoped_refptr<SequencedTaskRunner> task_runner =
// ThreadPool::CreateSequencedTaskRunner(
// {MayBlock(), TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
// task_runner->PostTask(FROM_HERE, BindOnce(...));
// task_runner->PostTask(FROM_HERE, BindOnce(...));
Expand All @@ -62,8 +84,7 @@ namespace base {
// Tasks posted with only traits defined in base/task/task_traits.h run on
// threads owned by the registered ThreadPoolInstance (i.e. not on the main
// thread). An embedder (e.g. Chrome) can define additional traits to make tasks
// run on threads of their choosing. TODO(https://crbug.com/863341): Make this a
// reality.
// run on threads of their choosing.
//
// Tasks posted with the same traits will be scheduled in the order they were
// posted. IMPORTANT: Please note however that, unless the traits imply a
Expand Down Expand Up @@ -171,6 +192,8 @@ BASE_EXPORT scoped_refptr<SequencedTaskRunner> CreateSequencedTaskRunner(
//
// |traits| requirements:
// - base::ThreadPool() must be specified.
// Note: Prefer the explicit (thread_pool.h) version of this API while we
// migrate this one to it.
// - Extension traits (e.g. BrowserThread) cannot be specified.
// - base::ThreadPolicy must be specified if the priority of the task runner
// will ever be increased from BEST_EFFORT.
Expand Down
18 changes: 9 additions & 9 deletions base/task/task_traits.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@
#include "base/traits_bag.h"
#include "build/build_config.h"

// TODO(gab): This is backwards, thread_pool.h should include task_traits.h
// but it this is necessary to have it in this direction during the migration
// from old code that used base::ThreadPool as a trait.
#include "base/task/thread_pool.h"

namespace base {

class PostTaskAndroid;
Expand Down Expand Up @@ -180,11 +185,6 @@ struct MayBlock {};
// In doubt, consult with //base/task/OWNERS.
struct WithBaseSyncPrimitives {};

// Tasks and task runners with this trait will run in the thread pool,
// concurrently with tasks on other task runners. If you need mutual exclusion
// between tasks, see base::PostTask::CreateSequencedTaskRunner.
struct ThreadPool {};

// Describes metadata for a single task or a group of tasks.
class BASE_EXPORT TaskTraits {
public:
Expand Down Expand Up @@ -212,14 +212,14 @@ class BASE_EXPORT TaskTraits {
// WithBaseSyncPrimitives in any order to the constructor.
//
// E.g.
// constexpr base::TaskTraits default_traits = {base::ThreadPool()};
// constexpr base::TaskTraits default_traits = {};
// constexpr base::TaskTraits user_visible_traits = {
// base::ThreadPool(), base::TaskPriority::USER_VISIBLE};
// base::TaskPriority::USER_VISIBLE};
// constexpr base::TaskTraits user_visible_may_block_traits = {
// base::ThreadPool(), base::TaskPriority::USER_VISIBLE, base::MayBlock()
// base::TaskPriority::USER_VISIBLE, base::MayBlock()
// };
// constexpr base::TaskTraits other_user_visible_may_block_traits = {
// base::ThreadPool(), base::MayBlock(), base::TaskPriority::USER_VISIBLE
// base::MayBlock(), base::TaskPriority::USER_VISIBLE
// };
template <class... ArgTypes,
class CheckArgumentsAreValid = std::enable_if_t<
Expand Down
10 changes: 9 additions & 1 deletion base/task/task_traits_extension_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,20 @@
namespace base {

TEST(TaskTraitsExtensionTest, NoExtension) {
constexpr TaskTraits traits = {ThreadPool()};
constexpr TaskTraits traits = {};

EXPECT_EQ(traits.extension_id(),
TaskTraitsExtensionStorage::kInvalidExtensionId);
}

TEST(TaskTraitsExtensionTest, ThreadPoolIsntAnExtension) {
constexpr TaskTraits traits = {base::ThreadPool()};

EXPECT_TRUE(traits.use_thread_pool());
EXPECT_EQ(traits.extension_id(),
TaskTraitsExtensionStorage::kInvalidExtensionId);
}

TEST(TaskTraitsExtensionTest, CreateWithOneExtensionTrait) {
constexpr TaskTraits traits = {TestExtensionEnumTrait::kB};

Expand Down
37 changes: 15 additions & 22 deletions base/task/task_traits_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
namespace base {

TEST(TaskTraitsTest, Default) {
constexpr TaskTraits traits = {ThreadPool()};
constexpr TaskTraits traits = {};
EXPECT_FALSE(traits.priority_set_explicitly());
EXPECT_EQ(TaskPriority::USER_BLOCKING, traits.priority());
EXPECT_FALSE(traits.shutdown_behavior_set_explicitly());
Expand All @@ -21,7 +21,7 @@ TEST(TaskTraitsTest, Default) {
}

TEST(TaskTraitsTest, TaskPriority) {
constexpr TaskTraits traits = {ThreadPool(), TaskPriority::BEST_EFFORT};
constexpr TaskTraits traits = {TaskPriority::BEST_EFFORT};
EXPECT_TRUE(traits.priority_set_explicitly());
EXPECT_EQ(TaskPriority::BEST_EFFORT, traits.priority());
EXPECT_FALSE(traits.shutdown_behavior_set_explicitly());
Expand All @@ -46,8 +46,7 @@ TEST(TaskTraitsTest, TaskShutdownBehavior) {
}

TEST(TaskTraitsTest, ThreadPolicy) {
constexpr TaskTraits traits = {ThreadPool(),
ThreadPolicy::MUST_USE_FOREGROUND};
constexpr TaskTraits traits = {ThreadPolicy::MUST_USE_FOREGROUND};
EXPECT_FALSE(traits.priority_set_explicitly());
EXPECT_EQ(TaskPriority::USER_BLOCKING, traits.priority());
EXPECT_FALSE(traits.shutdown_behavior_set_explicitly());
Expand All @@ -59,7 +58,7 @@ TEST(TaskTraitsTest, ThreadPolicy) {
}

TEST(TaskTraitsTest, MayBlock) {
constexpr TaskTraits traits = {ThreadPool(), MayBlock()};
constexpr TaskTraits traits = {MayBlock()};
EXPECT_FALSE(traits.priority_set_explicitly());
EXPECT_EQ(TaskPriority::USER_BLOCKING, traits.priority());
EXPECT_FALSE(traits.shutdown_behavior_set_explicitly());
Expand All @@ -71,7 +70,7 @@ TEST(TaskTraitsTest, MayBlock) {
}

TEST(TaskTraitsTest, WithBaseSyncPrimitives) {
constexpr TaskTraits traits = {ThreadPool(), WithBaseSyncPrimitives()};
constexpr TaskTraits traits = {WithBaseSyncPrimitives()};
EXPECT_FALSE(traits.priority_set_explicitly());
EXPECT_EQ(TaskPriority::USER_BLOCKING, traits.priority());
EXPECT_FALSE(traits.shutdown_behavior_set_explicitly());
Expand All @@ -84,15 +83,15 @@ TEST(TaskTraitsTest, WithBaseSyncPrimitives) {

TEST(TaskTraitsTest, UpdatePriority) {
{
TaskTraits traits = {ThreadPool()};
TaskTraits traits = {};
EXPECT_FALSE(traits.priority_set_explicitly());
traits.UpdatePriority(TaskPriority::BEST_EFFORT);
EXPECT_EQ(TaskPriority::BEST_EFFORT, traits.priority());
EXPECT_TRUE(traits.priority_set_explicitly());
}

{
TaskTraits traits = {ThreadPool(), TaskPriority::USER_VISIBLE};
TaskTraits traits = {TaskPriority::USER_VISIBLE};
EXPECT_TRUE(traits.priority_set_explicitly());
traits.UpdatePriority(TaskPriority::BEST_EFFORT);
EXPECT_EQ(TaskPriority::BEST_EFFORT, traits.priority());
Expand All @@ -102,27 +101,24 @@ TEST(TaskTraitsTest, UpdatePriority) {

TEST(TaskTraitsTest, InheritPriority) {
{
TaskTraits traits = {ThreadPool()};
TaskTraits traits = {};
traits.InheritPriority(TaskPriority::BEST_EFFORT);
EXPECT_EQ(TaskPriority::BEST_EFFORT, traits.priority());
EXPECT_FALSE(traits.priority_set_explicitly());
}

{
TaskTraits traits = {ThreadPool(), TaskPriority::USER_VISIBLE};
TaskTraits traits = {TaskPriority::USER_VISIBLE};
traits.InheritPriority(TaskPriority::BEST_EFFORT);
EXPECT_EQ(TaskPriority::USER_VISIBLE, traits.priority());
EXPECT_TRUE(traits.priority_set_explicitly());
}
}

TEST(TaskTraitsTest, MultipleTraits) {
constexpr TaskTraits traits = {ThreadPool(),
TaskPriority::BEST_EFFORT,
TaskShutdownBehavior::BLOCK_SHUTDOWN,
ThreadPolicy::MUST_USE_FOREGROUND,
MayBlock(),
WithBaseSyncPrimitives()};
constexpr TaskTraits traits = {
TaskPriority::BEST_EFFORT, TaskShutdownBehavior::BLOCK_SHUTDOWN,
ThreadPolicy::MUST_USE_FOREGROUND, MayBlock(), WithBaseSyncPrimitives()};
EXPECT_TRUE(traits.priority_set_explicitly());
EXPECT_EQ(TaskPriority::BEST_EFFORT, traits.priority());
EXPECT_TRUE(traits.shutdown_behavior_set_explicitly());
Expand All @@ -134,12 +130,9 @@ TEST(TaskTraitsTest, MultipleTraits) {
}

TEST(TaskTraitsTest, Copy) {
constexpr TaskTraits traits = {ThreadPool(),
TaskPriority::BEST_EFFORT,
TaskShutdownBehavior::BLOCK_SHUTDOWN,
ThreadPolicy::MUST_USE_FOREGROUND,
MayBlock(),
WithBaseSyncPrimitives()};
constexpr TaskTraits traits = {
TaskPriority::BEST_EFFORT, TaskShutdownBehavior::BLOCK_SHUTDOWN,
ThreadPolicy::MUST_USE_FOREGROUND, MayBlock(), WithBaseSyncPrimitives()};
constexpr TaskTraits traits_copy(traits);

EXPECT_EQ(traits, traits_copy);
Expand Down
137 changes: 137 additions & 0 deletions base/task/thread_pool.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
// Copyright 2019 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/task/thread_pool.h"

#include "base/logging.h"
#include "base/task/scoped_set_task_priority_for_current_thread.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool/thread_pool_impl.h"
#include "base/task/thread_pool/thread_pool_instance.h"
#include "base/threading/post_task_and_reply_impl.h"

namespace base {

namespace {

class PostTaskAndReplyWithTraitsTaskRunner
: public internal::PostTaskAndReplyImpl {
public:
explicit PostTaskAndReplyWithTraitsTaskRunner(const TaskTraits& traits)
: traits_(traits) {}

private:
bool PostTask(const Location& from_here, OnceClosure task) override {
ThreadPool::PostTask(from_here, traits_, std::move(task));
return true;
}

const TaskTraits traits_;
};

// Returns TaskTraits based on |traits|. If TaskPriority hasn't been set
// explicitly in |traits|, the returned TaskTraits will inherit the current
// TaskPriority.
TaskTraits GetTaskTraitsWithExplicitPriority(TaskTraits traits) {
traits.InheritPriority(internal::GetTaskPriorityForCurrentThread());
return traits;
}

internal::ThreadPoolImpl* GetThreadPoolImpl() {
auto* instance = ThreadPoolInstance::Get();
DCHECK(instance)
<< "Ref. Prerequisite section of base/task/thread_pool.h.\n"
"Hint: if this is in a unit test, you're likely merely missing a "
"base::test::TaskEnvironment member in your fixture (or your fixture "
"is using a base::test::SingleThreadTaskEnvironment and now needs a "
"full base::test::TaskEnvironment).\n";
return static_cast<internal::ThreadPoolImpl*>(instance);
}

} // namespace

// static
bool ThreadPool::PostTask(const Location& from_here, OnceClosure task) {
return ThreadPool::PostDelayedTask(from_here, std::move(task), TimeDelta());
}

// static
bool ThreadPool::PostDelayedTask(const Location& from_here,
OnceClosure task,
TimeDelta delay) {
return ThreadPool::PostDelayedTask(from_here, {}, std::move(task), delay);
}

// static
bool ThreadPool::PostTaskAndReply(const Location& from_here,
OnceClosure task,
OnceClosure reply) {
return ThreadPool::PostTaskAndReply(from_here, {}, std::move(task),
std::move(reply));
}

// static
bool ThreadPool::PostTask(const Location& from_here,
const TaskTraits& traits,
OnceClosure task) {
return ThreadPool::PostDelayedTask(from_here, traits, std::move(task),
TimeDelta());
}

// static
bool ThreadPool::PostDelayedTask(const Location& from_here,
const TaskTraits& traits,
OnceClosure task,
TimeDelta delay) {
const TaskTraits adjusted_traits = GetTaskTraitsWithExplicitPriority(traits);
return GetThreadPoolImpl()->PostDelayedTask(from_here, adjusted_traits,
std::move(task), delay);
}

// static
bool ThreadPool::PostTaskAndReply(const Location& from_here,
const TaskTraits& traits,
OnceClosure task,
OnceClosure reply) {
return PostTaskAndReplyWithTraitsTaskRunner(traits).PostTaskAndReply(
from_here, std::move(task), std::move(reply));
}

// static
scoped_refptr<TaskRunner> ThreadPool::CreateTaskRunner(
const TaskTraits& traits) {
return GetThreadPoolImpl()->CreateTaskRunner(traits);
}

// static
scoped_refptr<SequencedTaskRunner> ThreadPool::CreateSequencedTaskRunner(
const TaskTraits& traits) {
return GetThreadPoolImpl()->CreateSequencedTaskRunner(traits);
}

// static
scoped_refptr<UpdateableSequencedTaskRunner>
ThreadPool::CreateUpdateableSequencedTaskRunner(const TaskTraits& traits) {
const TaskTraits adjusted_traits = GetTaskTraitsWithExplicitPriority(traits);
return GetThreadPoolImpl()->CreateUpdateableSequencedTaskRunner(
adjusted_traits);
}

// static
scoped_refptr<SingleThreadTaskRunner> ThreadPool::CreateSingleThreadTaskRunner(
const TaskTraits& traits,
SingleThreadTaskRunnerThreadMode thread_mode) {
return GetThreadPoolImpl()->CreateSingleThreadTaskRunner(traits, thread_mode);
}

#if defined(OS_WIN)
// static
scoped_refptr<SingleThreadTaskRunner> ThreadPool::CreateCOMSTATaskRunner(
const TaskTraits& traits,
SingleThreadTaskRunnerThreadMode thread_mode) {
return GetThreadPoolImpl()->CreateCOMSTATaskRunner(traits, thread_mode);
}
#endif // defined(OS_WIN)

} // namespace base
Loading

0 comments on commit 43de5c4

Please sign in to comment.