blob: c1e52ed0f07476d97e006a10cc05b4728ef82052 [file] [log] [blame]
// Copyright 2016 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_TASK_TRAITS_H_
#define BASE_TASK_TASK_TRAITS_H_
#include <stdint.h>
#include <iosfwd>
#include <tuple>
#include <type_traits>
#include <utility>
#include "base/base_export.h"
#include "base/logging.h"
#include "base/task/task_traits_extension.h"
#include "base/traits_bag.h"
#include "build/build_config.h"
namespace base {
class PostTaskAndroid;
// Valid priorities supported by the task scheduling infrastructure.
//
// Note: internal algorithms depend on priorities being expressed as a
// continuous zero-based list from lowest to highest priority. Users of this API
// shouldn't otherwise care about nor use the underlying values.
//
// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.base.task
enum class TaskPriority : uint8_t {
// This will always be equal to the lowest priority available.
LOWEST = 0,
// This task will only start running when machine resources are available. The
// application may preempt the task if it expects that resources will soon be
// needed by work of higher priority. Dependending on the ThreadPolicy, the
// task may run on a thread that is likely to be descheduled when higher
// priority work arrives (in this process or another).
//
// Examples:
// - Reporting metrics.
// - Persisting data to disk.
// - Loading data that is required for a potential future user interaction
// (Note: Use CreateUpdateableSequencedTaskRunner() to increase the priority
// when that user interactions happens).
BEST_EFFORT = LOWEST,
// The result of this task is visible to the user (in the UI or as a
// side-effect on the system) but it is not an immediate response to a user
// interaction.
//
// Examples:
// - Updating the UI to reflect progress on a long task.
// - Downloading a file requested by the user.
// - Loading an image that is displayed in the UI but is non-critical.
USER_VISIBLE,
// This task affects UI immediately after a user interaction.
//
// Example:
// - Loading and rendering a web page after the user clicks a link.
// - Sorting suggestions after the user types a character in the omnibox.
USER_BLOCKING,
// This will always be equal to the highest priority available.
HIGHEST = USER_BLOCKING
};
// Valid shutdown behaviors supported by the thread pool.
enum class TaskShutdownBehavior : uint8_t {
// Tasks posted with this mode which have not started executing before
// shutdown is initiated will never run. Tasks with this mode running at
// shutdown will be ignored (the worker will not be joined).
//
// This option provides a nice way to post stuff you don't want blocking
// shutdown. For example, you might be doing a slow DNS lookup and if it's
// blocked on the OS, you may not want to stop shutdown, since the result
// doesn't really matter at that point.
//
// However, you need to be very careful what you do in your callback when you
// use this option. Since the thread will continue to run until the OS
// terminates the process, the app can be in the process of tearing down when
// you're running. This means any singletons or global objects you use may
// suddenly become invalid out from under you. For this reason, it's best to
// use this only for slow but simple operations like the DNS example.
CONTINUE_ON_SHUTDOWN,
// Tasks posted with this mode that have not started executing at
// shutdown will never run. However, any task that has already begun
// executing when shutdown is invoked will be allowed to continue and
// will block shutdown until completion.
//
// Note: Because ThreadPoolInstance::Shutdown() may block while these tasks
// are executing, care must be taken to ensure that they do not block on the
// thread that called ThreadPoolInstance::Shutdown(), as this may lead to
// deadlock.
SKIP_ON_SHUTDOWN,
// Tasks posted with this mode before shutdown is complete will block shutdown
// until they're executed. Generally, this should be used only to save
// critical user data.
//
// Note: Background threads will be promoted to normal threads at shutdown
// (i.e. TaskPriority::BEST_EFFORT + TaskShutdownBehavior::BLOCK_SHUTDOWN will
// resolve without a priority inversion).
BLOCK_SHUTDOWN,
};
// Determines at which thread priority a task may run.
//
// ThreadPolicy and priority updates
// ---------------------------------
//
// If the TaskPriority of an UpdateableSequencedTaskRunner is increased while
// one of its tasks is running at background thread priority, the task's
// execution will have to complete at background thread priority (may take a
// long time) before the next task can be scheduled with the new TaskPriority.
// If it is important that priority increases take effect quickly,
// MUST_USE_FOREGROUND should be used to prevent the tasks from running at
// background thread priority. If it is important to minimize impact on the
// rest on the system when the TaskPriority is BEST_EFFORT, PREFER_BACKGROUND
// should be used.
//
// ThreadPolicy and priority inversions
// ------------------------------------
//
// A priority inversion occurs when a task running at background thread
// priority is descheduled while holding a resource needed by a thread of
// higher priority. MUST_USE_FOREGROUND can be combined with BEST_EFFORT to
// indicate that a task has a low priority, but shouldn't run at background
// thread priority in order to avoid priority inversions. Please consult with
// //base/task/OWNERS if you suspect a priority inversion.
enum class ThreadPolicy : uint8_t {
// The task runs at background thread priority if:
// - The TaskPriority is BEST_EFFORT.
// - Background thread priority is supported by the platform (see
// environment_config_unittest.cc).
// - No extension trait (e.g. BrowserThread) is used.
// Otherwise, it runs at normal thread priority.
PREFER_BACKGROUND,
// The task runs at normal thread priority, irrespective of its TaskPriority.
MUST_USE_FOREGROUND
};
// Tasks with this trait may block. This includes but is not limited to tasks
// that wait on synchronous file I/O operations: read or write a file from disk,
// interact with a pipe or a socket, rename or delete a file, enumerate files in
// a directory, etc. This trait isn't required for the mere use of locks. For
// tasks that block on base/ synchronization primitives, see the
// WithBaseSyncPrimitives trait.
struct MayBlock {};
// DEPRECATED. Use base::ScopedAllowBaseSyncPrimitives(ForTesting) instead.
//
// Tasks with this trait will pass base::AssertBaseSyncPrimitivesAllowed(), i.e.
// will be allowed on the following methods :
// - base::WaitableEvent::Wait
// - base::ConditionVariable::Wait
// - base::PlatformThread::Join
// - base::PlatformThread::Sleep
// - base::Process::WaitForExit
// - base::Process::WaitForExitWithTimeout
//
// Tasks should generally not use these methods.
//
// Instead of waiting on a WaitableEvent or a ConditionVariable, put the work
// that should happen after the wait in a callback and post that callback from
// where the WaitableEvent or ConditionVariable would have been signaled. If
// something needs to be scheduled after many tasks have executed, use
// base::BarrierClosure.
//
// On Windows, join processes asynchronously using base::win::ObjectWatcher.
//
// MayBlock() must be specified in conjunction with this trait if and only if
// removing usage of methods listed above in the labeled tasks would still
// result in tasks that may block (per MayBlock()'s definition).
//
// 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:
// ValidTrait ensures TaskTraits' constructor only accepts appropriate types.
struct ValidTrait {
ValidTrait(TaskPriority);
ValidTrait(TaskShutdownBehavior);
ValidTrait(ThreadPolicy);
ValidTrait(MayBlock);
ValidTrait(WithBaseSyncPrimitives);
ValidTrait(ThreadPool);
};
// Invoking this constructor without arguments produces TaskTraits that are
// appropriate for 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
// (ThreadPoolInstance implementation is free to choose a fitting
// default).
//
// To get TaskTraits for tasks that require stricter guarantees and/or know
// the specific TaskPriority appropriate for them, provide arguments of type
// TaskPriority, TaskShutdownBehavior, ThreadPolicy, MayBlock and/or
// WithBaseSyncPrimitives in any order to the constructor.
//
// E.g.
// constexpr base::TaskTraits default_traits = {base::ThreadPool()};
// constexpr base::TaskTraits user_visible_traits = {
// base::ThreadPool(), base::TaskPriority::USER_VISIBLE};
// constexpr base::TaskTraits user_visible_may_block_traits = {
// base::ThreadPool(), base::TaskPriority::USER_VISIBLE, base::MayBlock()
// };
// constexpr base::TaskTraits other_user_visible_may_block_traits = {
// base::ThreadPool(), base::MayBlock(), base::TaskPriority::USER_VISIBLE
// };
template <class... ArgTypes,
class CheckArgumentsAreValid = std::enable_if_t<
trait_helpers::AreValidTraits<ValidTrait, ArgTypes...>::value ||
trait_helpers::AreValidTraitsForExtension<ArgTypes...>::value>>
constexpr TaskTraits(ArgTypes... args)
: extension_(trait_helpers::GetTaskTraitsExtension(
trait_helpers::AreValidTraits<ValidTrait, ArgTypes...>{},
args...)),
priority_(
static_cast<uint8_t>(
trait_helpers::GetEnum<TaskPriority,
TaskPriority::USER_BLOCKING>(args...)) |
(trait_helpers::HasTrait<TaskPriority, ArgTypes...>()
? kIsExplicitFlag
: 0)),
shutdown_behavior_(
static_cast<uint8_t>(
trait_helpers::GetEnum<TaskShutdownBehavior,
TaskShutdownBehavior::SKIP_ON_SHUTDOWN>(
args...)) |
(trait_helpers::HasTrait<TaskShutdownBehavior, ArgTypes...>()
? kIsExplicitFlag
: 0)),
thread_policy_(
static_cast<uint8_t>(
trait_helpers::GetEnum<ThreadPolicy,
ThreadPolicy::PREFER_BACKGROUND>(
args...)) |
(trait_helpers::HasTrait<ThreadPolicy, ArgTypes...>()
? kIsExplicitFlag
: 0)),
may_block_(trait_helpers::HasTrait<MayBlock, ArgTypes...>()),
with_base_sync_primitives_(
trait_helpers::HasTrait<WithBaseSyncPrimitives, ArgTypes...>()),
use_thread_pool_(trait_helpers::HasTrait<ThreadPool, ArgTypes...>()) {
constexpr bool has_thread_pool =
trait_helpers::HasTrait<ThreadPool, ArgTypes...>();
constexpr bool has_extension =
!trait_helpers::AreValidTraits<ValidTrait, ArgTypes...>::value;
static_assert(
has_thread_pool ^ has_extension,
"Traits must explicitly specify a destination (e.g. ThreadPool or a "
"named thread like BrowserThread)");
}
constexpr TaskTraits(const TaskTraits& other) = default;
TaskTraits& operator=(const TaskTraits& other) = default;
// TODO(eseckler): Default the comparison operator once C++20 arrives.
bool operator==(const TaskTraits& other) const {
static_assert(sizeof(TaskTraits) == 15,
"Update comparison operator when TaskTraits change");
return extension_ == other.extension_ && priority_ == other.priority_ &&
shutdown_behavior_ == other.shutdown_behavior_ &&
thread_policy_ == other.thread_policy_ &&
may_block_ == other.may_block_ &&
with_base_sync_primitives_ == other.with_base_sync_primitives_ &&
use_thread_pool_ == other.use_thread_pool_;
}
// Sets the priority of tasks with these traits to |priority|.
void UpdatePriority(TaskPriority priority) {
priority_ = static_cast<uint8_t>(priority) | kIsExplicitFlag;
}
// Sets the priority to |priority| if it wasn't explicitly set before.
void InheritPriority(TaskPriority priority) {
if (priority_set_explicitly())
return;
priority_ = static_cast<uint8_t>(priority);
}
// Returns true if the priority was set explicitly.
constexpr bool priority_set_explicitly() const {
return priority_ & kIsExplicitFlag;
}
// Returns the priority of tasks with these traits.
constexpr TaskPriority priority() const {
return static_cast<TaskPriority>(priority_ & ~kIsExplicitFlag);
}
// Returns true if the shutdown behavior was set explicitly.
constexpr bool shutdown_behavior_set_explicitly() const {
return shutdown_behavior_ & kIsExplicitFlag;
}
// Returns the shutdown behavior of tasks with these traits.
constexpr TaskShutdownBehavior shutdown_behavior() const {
return static_cast<TaskShutdownBehavior>(shutdown_behavior_ &
~kIsExplicitFlag);
}
// Returns true if the thread policy was set explicitly.
constexpr bool thread_policy_set_explicitly() const {
return thread_policy_ & kIsExplicitFlag;
}
// Returns the thread policy of tasks with these traits.
constexpr ThreadPolicy thread_policy() const {
return static_cast<ThreadPolicy>(thread_policy_ & ~kIsExplicitFlag);
}
// Returns true if tasks with these traits may block.
constexpr bool may_block() const { return may_block_; }
// Returns true if tasks with these traits may use base/ sync primitives.
constexpr bool with_base_sync_primitives() const {
return with_base_sync_primitives_;
}
// Returns true if tasks with these traits execute on the thread pool.
constexpr bool use_thread_pool() const { return use_thread_pool_; }
uint8_t extension_id() const { return extension_.extension_id; }
// Access the extension data by parsing it into the provided extension type.
// See task_traits_extension.h for requirements on the extension type.
template <class TaskTraitsExtension>
const TaskTraitsExtension GetExtension() const {
DCHECK_EQ(TaskTraitsExtension::kExtensionId, extension_.extension_id);
return TaskTraitsExtension::Parse(extension_);
}
private:
friend PostTaskAndroid;
// For use by PostTaskAndroid.
TaskTraits(bool priority_set_explicitly,
TaskPriority priority,
bool may_block,
bool use_thread_pool,
TaskTraitsExtensionStorage extension)
: extension_(extension),
priority_(static_cast<uint8_t>(priority) |
(priority_set_explicitly ? kIsExplicitFlag : 0)),
shutdown_behavior_(
static_cast<uint8_t>(TaskShutdownBehavior::SKIP_ON_SHUTDOWN)),
thread_policy_(static_cast<uint8_t>(ThreadPolicy::PREFER_BACKGROUND)),
may_block_(may_block),
with_base_sync_primitives_(false),
use_thread_pool_(use_thread_pool) {
static_assert(sizeof(TaskTraits) == 15, "Keep this constructor up to date");
}
// This bit is set in |priority_|, |shutdown_behavior_| and |thread_policy_|
// when the value was set explicitly.
static constexpr uint8_t kIsExplicitFlag = 0x80;
// Ordered for packing.
TaskTraitsExtensionStorage extension_;
uint8_t priority_;
uint8_t shutdown_behavior_;
uint8_t thread_policy_;
bool may_block_;
bool with_base_sync_primitives_;
bool use_thread_pool_;
};
// Returns string literals for the enums defined in this file. These methods
// should only be used for tracing and debugging.
BASE_EXPORT const char* TaskPriorityToString(TaskPriority task_priority);
BASE_EXPORT const char* TaskShutdownBehaviorToString(
TaskShutdownBehavior task_priority);
// Stream operators so that the enums defined in this file can be used in
// DCHECK and EXPECT statements.
BASE_EXPORT std::ostream& operator<<(std::ostream& os,
const TaskPriority& shutdown_behavior);
BASE_EXPORT std::ostream& operator<<(
std::ostream& os,
const TaskShutdownBehavior& shutdown_behavior);
} // namespace base
#endif // BASE_TASK_TASK_TRAITS_H_