diff --git a/base/BUILD.gn b/base/BUILD.gn index 27c008dba74fd5..bd898aa58c8760 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn @@ -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", diff --git a/base/task/post_task.h b/base/task/post_task.h index 00c0fffaf83dd9..02d8e4e2ac9d0a 100644 --- a/base/task/post_task.h +++ b/base/task/post_task.h @@ -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 task_runner = // CreateSequencedTaskRunner({ThreadPool()}); // task_runner->PostTask(FROM_HERE, BindOnce(...)); // task_runner->PostTask(FROM_HERE, BindOnce(...)); +// modern equivalent: +// scoped_refptr 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 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 task_runner = +// ThreadPool::CreateSequencedTaskRunner( // {MayBlock(), TaskShutdownBehavior::SKIP_ON_SHUTDOWN}); // task_runner->PostTask(FROM_HERE, BindOnce(...)); // task_runner->PostTask(FROM_HERE, BindOnce(...)); @@ -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 @@ -171,6 +192,8 @@ BASE_EXPORT scoped_refptr 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. diff --git a/base/task/task_traits.h b/base/task/task_traits.h index a2064b1fd1bea0..5755418c430e13 100644 --- a/base/task/task_traits.h +++ b/base/task/task_traits.h @@ -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; @@ -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: @@ -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 (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 ThreadPool::CreateTaskRunner( + const TaskTraits& traits) { + return GetThreadPoolImpl()->CreateTaskRunner(traits); +} + +// static +scoped_refptr ThreadPool::CreateSequencedTaskRunner( + const TaskTraits& traits) { + return GetThreadPoolImpl()->CreateSequencedTaskRunner(traits); +} + +// static +scoped_refptr +ThreadPool::CreateUpdateableSequencedTaskRunner(const TaskTraits& traits) { + const TaskTraits adjusted_traits = GetTaskTraitsWithExplicitPriority(traits); + return GetThreadPoolImpl()->CreateUpdateableSequencedTaskRunner( + adjusted_traits); +} + +// static +scoped_refptr ThreadPool::CreateSingleThreadTaskRunner( + const TaskTraits& traits, + SingleThreadTaskRunnerThreadMode thread_mode) { + return GetThreadPoolImpl()->CreateSingleThreadTaskRunner(traits, thread_mode); +} + +#if defined(OS_WIN) +// static +scoped_refptr ThreadPool::CreateCOMSTATaskRunner( + const TaskTraits& traits, + SingleThreadTaskRunnerThreadMode thread_mode) { + return GetThreadPoolImpl()->CreateCOMSTATaskRunner(traits, thread_mode); +} +#endif // defined(OS_WIN) + +} // namespace base diff --git a/base/task/thread_pool.h b/base/task/thread_pool.h new file mode 100644 index 00000000000000..ca67476b15c3a8 --- /dev/null +++ b/base/task/thread_pool.h @@ -0,0 +1,249 @@ +// 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. + +#ifndef BASE_TASK_THREAD_POOL_H_ +#define BASE_TASK_THREAD_POOL_H_ + +#include +#include + +namespace base { +// TODO(gab): thread_pool.h should include task_traits.h but it can't during the +// migration because task_traits.h has to include thread_pool.h to get the old +// base::ThreadPool() trait constructor and that would create a circular +// dependency. Some of the includes below result in an extended version of this +// circular dependency. These forward-declarations are temporarily required for +// the duration of the migration. +enum class TaskPriority : uint8_t; +enum class TaskShutdownBehavior : uint8_t; +enum class ThreadPolicy : uint8_t; +struct MayBlock; +struct WithBaseSyncPrimitives; +class TaskTraits; +// UpdateableSequencedTaskRunner is part of this dance too because +// updateable_sequenced_task_runner.h includes task_traits.h +class UpdateableSequencedTaskRunner; +} // namespace base + +#include "base/base_export.h" +#include "base/bind.h" +#include "base/callback.h" +#include "base/callback_helpers.h" +#include "base/location.h" +#include "base/memory/scoped_refptr.h" +#include "base/post_task_and_reply_with_result_internal.h" +#include "base/sequenced_task_runner.h" +#include "base/single_thread_task_runner.h" +#include "base/task/single_thread_task_runner_thread_mode.h" +#include "base/task_runner.h" +#include "base/time/time.h" +#include "build/build_config.h" + +namespace base { + +// This is the interface to post tasks to base's thread pool. +// +// To post a simple one-off task with default traits: +// base::ThreadPool::PostTask(FROM_HERE, base::BindOnce(...)); +// +// To post a high priority one-off task to respond to a user interaction: +// base::ThreadPool::PostTask( +// FROM_HERE, +// {base::TaskPriority::USER_BLOCKING}, +// base::BindOnce(...)); +// +// To post tasks that must run in sequence with default traits: +// scoped_refptr task_runner = +// base::ThreadPool::CreateSequencedTaskRunner(); +// task_runner->PostTask(FROM_HERE, base::BindOnce(...)); +// task_runner->PostTask(FROM_HERE, base::BindOnce(...)); +// +// To post tasks that may block, must run in sequence and can be skipped on +// shutdown: +// scoped_refptr task_runner = +// base::ThreadPool::CreateSequencedTaskRunner( +// {MayBlock(), TaskShutdownBehavior::SKIP_ON_SHUTDOWN}); +// task_runner->PostTask(FROM_HERE, base::BindOnce(...)); +// task_runner->PostTask(FROM_HERE, base::BindOnce(...)); +// +// The default traits apply to tasks that: +// (1) don't block (ref. MayBlock() and WithBaseSyncPrimitives()), +// (2) prefer inheriting the current priority to specifying their own, and +// (3) can either block shutdown or be skipped on shutdown +// (implementation is free to choose a fitting default). +// Explicit traits must be specified for tasks for which these loose +// requirements are not sufficient. +// +// Prerequisite: A ThreadPoolInstance must have been registered for the current +// process via ThreadPoolInstance::Set() before the API below can be invoked. +// This is typically done during the initialization phase in each process. If +// your code is not running in that phase, you most likely don't have to worry +// about this. You will encounter DCHECKs or nullptr dereferences if this is +// violated. For tests, use base::test::TaskEnvironment. +class BASE_EXPORT ThreadPool { + public: + // base::ThreadPool is meant to be a static API. Do not use this constructor + // in new code! It is a temporary hack to support the old base::ThreadPool() + // trait during the migration to static base::ThreadPool:: APIs. + // 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::ThreadPool::CreateSequencedTaskRunner. + ThreadPool() = default; + + // Equivalent to calling PostTask with default TaskTraits. + static bool PostTask(const Location& from_here, OnceClosure task); + inline static bool PostTask(OnceClosure task, + const Location& from_here = Location::Current()) { + return PostTask(from_here, std::move(task)); + } + + // Equivalent to calling PostDelayedTask with default TaskTraits. + // + // Use PostDelayedTask to specify a BEST_EFFORT priority if the task doesn't + // have to run as soon as |delay| expires. + static bool PostDelayedTask(const Location& from_here, + OnceClosure task, + TimeDelta delay); + + // Equivalent to calling PostTaskAndReply with default TaskTraits. + static bool PostTaskAndReply(const Location& from_here, + OnceClosure task, + OnceClosure reply); + + // Equivalent to calling PostTaskAndReplyWithResult with default TaskTraits. + // + // Though RepeatingCallback is convertible to OnceCallback, we need a + // CallbackType template since we can not use template deduction and object + // conversion at once on the overload resolution. + // TODO(crbug.com/714018): Update all callers of the RepeatingCallback version + // to use OnceCallback and remove the CallbackType template. + template