1// Copyright 2016 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef BASE_TASK_TASK_TRAITS_H_
6#define BASE_TASK_TASK_TRAITS_H_
7
8#include <stdint.h>
9
10#include <iosfwd>
11#include <tuple>
12#include <type_traits>
13#include <utility>
14
15#include "base/base_export.h"
16#include "base/logging.h"
17#include "base/task/task_traits_extension.h"
18#include "base/traits_bag.h"
19#include "build/build_config.h"
20
21namespace base {
22
23class PostTaskAndroid;
24
25// Valid priorities supported by the task scheduling infrastructure.
26// Note: internal algorithms depend on priorities being expressed as a
27// continuous zero-based list from lowest to highest priority. Users of this API
28// shouldn't otherwise care about nor use the underlying values.
29// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.base.task
30enum class TaskPriority {
31 // This will always be equal to the lowest priority available.
32 LOWEST = 0,
33 // This task will only be scheduled when machine resources are available. Once
34 // running, it may be descheduled if higher priority work arrives (in this
35 // process or another) and its running on a non-critical thread.
36 BEST_EFFORT = LOWEST,
37 // This task affects UI or responsiveness of future user interactions. It is
38 // not an immediate response to a user interaction.
39 // Examples:
40 // - Updating the UI to reflect progress on a long task.
41 // - Loading data that might be shown in the UI after a future user
42 // interaction.
43 USER_VISIBLE,
44 // This task affects UI immediately after a user interaction.
45 // Example: Generating data shown in the UI immediately after a click.
46 USER_BLOCKING,
47 // This will always be equal to the highest priority available.
48 HIGHEST = USER_BLOCKING,
49};
50
51// Valid shutdown behaviors supported by the thread pool.
52enum class TaskShutdownBehavior {
53 // Tasks posted with this mode which have not started executing before
54 // shutdown is initiated will never run. Tasks with this mode running at
55 // shutdown will be ignored (the worker will not be joined).
56 //
57 // This option provides a nice way to post stuff you don't want blocking
58 // shutdown. For example, you might be doing a slow DNS lookup and if it's
59 // blocked on the OS, you may not want to stop shutdown, since the result
60 // doesn't really matter at that point.
61 //
62 // However, you need to be very careful what you do in your callback when you
63 // use this option. Since the thread will continue to run until the OS
64 // terminates the process, the app can be in the process of tearing down when
65 // you're running. This means any singletons or global objects you use may
66 // suddenly become invalid out from under you. For this reason, it's best to
67 // use this only for slow but simple operations like the DNS example.
68 CONTINUE_ON_SHUTDOWN,
69
70 // Tasks posted with this mode that have not started executing at
71 // shutdown will never run. However, any task that has already begun
72 // executing when shutdown is invoked will be allowed to continue and
73 // will block shutdown until completion.
74 //
75 // Note: Because ThreadPool::Shutdown() may block while these tasks are
76 // executing, care must be taken to ensure that they do not block on the
77 // thread that called ThreadPool::Shutdown(), as this may lead to deadlock.
78 SKIP_ON_SHUTDOWN,
79
80 // Tasks posted with this mode before shutdown is complete will block shutdown
81 // until they're executed. Generally, this should be used only to save
82 // critical user data.
83 //
84 // Note: Background threads will be promoted to normal threads at shutdown
85 // (i.e. TaskPriority::BEST_EFFORT + TaskShutdownBehavior::BLOCK_SHUTDOWN will
86 // resolve without a priority inversion).
87 BLOCK_SHUTDOWN,
88};
89
90// Tasks with this trait may block. This includes but is not limited to tasks
91// that wait on synchronous file I/O operations: read or write a file from disk,
92// interact with a pipe or a socket, rename or delete a file, enumerate files in
93// a directory, etc. This trait isn't required for the mere use of locks. For
94// tasks that block on base/ synchronization primitives, see the
95// WithBaseSyncPrimitives trait.
96struct MayBlock {};
97
98// DEPRECATED. Use base::ScopedAllowBaseSyncPrimitives(ForTesting) instead.
99//
100// Tasks with this trait will pass base::AssertBaseSyncPrimitivesAllowed(), i.e.
101// will be allowed on the following methods :
102// - base::WaitableEvent::Wait
103// - base::ConditionVariable::Wait
104// - base::PlatformThread::Join
105// - base::PlatformThread::Sleep
106// - base::Process::WaitForExit
107// - base::Process::WaitForExitWithTimeout
108//
109// Tasks should generally not use these methods.
110//
111// Instead of waiting on a WaitableEvent or a ConditionVariable, put the work
112// that should happen after the wait in a callback and post that callback from
113// where the WaitableEvent or ConditionVariable would have been signaled. If
114// something needs to be scheduled after many tasks have executed, use
115// base::BarrierClosure.
116//
117// On Windows, join processes asynchronously using base::win::ObjectWatcher.
118//
119// MayBlock() must be specified in conjunction with this trait if and only if
120// removing usage of methods listed above in the labeled tasks would still
121// result in tasks that may block (per MayBlock()'s definition).
122//
123// In doubt, consult with //base/task/OWNERS.
124struct WithBaseSyncPrimitives {};
125
126// Describes immutable metadata for a single task or a group of tasks.
127class BASE_EXPORT TaskTraits {
128 public:
129 // ValidTrait ensures TaskTraits' constructor only accepts appropriate types.
130 struct ValidTrait {
131 ValidTrait(TaskPriority);
132 ValidTrait(TaskShutdownBehavior);
133 ValidTrait(MayBlock);
134 ValidTrait(WithBaseSyncPrimitives);
135 };
136
137 // Invoking this constructor without arguments produces TaskTraits that are
138 // appropriate for tasks that
139 // (1) don't block (ref. MayBlock() and WithBaseSyncPrimitives()),
140 // (2) prefer inheriting the current priority to specifying their own, and
141 // (3) can either block shutdown or be skipped on shutdown
142 // (ThreadPool implementation is free to choose a fitting default).
143 //
144 // To get TaskTraits for tasks that require stricter guarantees and/or know
145 // the specific TaskPriority appropriate for them, provide arguments of type
146 // TaskPriority, TaskShutdownBehavior, MayBlock, and/or WithBaseSyncPrimitives
147 // in any order to the constructor.
148 //
149 // E.g.
150 // constexpr base::TaskTraits default_traits = {};
151 // constexpr base::TaskTraits user_visible_traits =
152 // {base::TaskPriority::USER_VISIBLE};
153 // constexpr base::TaskTraits user_visible_may_block_traits = {
154 // base::TaskPriority::USER_VISIBLE, base::MayBlock()};
155 // constexpr base::TaskTraits other_user_visible_may_block_traits = {
156 // base::MayBlock(), base::TaskPriority::USER_VISIBLE};
157 template <class... ArgTypes,
158 class CheckArgumentsAreValid = std::enable_if_t<
159 trait_helpers::AreValidTraits<ValidTrait, ArgTypes...>::value ||
160 trait_helpers::AreValidTraitsForExtension<ArgTypes...>::value>>
161 constexpr TaskTraits(ArgTypes... args)
162 : extension_(trait_helpers::GetTaskTraitsExtension(
163 trait_helpers::AreValidTraits<ValidTrait, ArgTypes...>{},
164 args...)),
165 priority_(
166 trait_helpers::GetEnum<TaskPriority, TaskPriority::USER_VISIBLE>(
167 args...)),
168 shutdown_behavior_(
169 trait_helpers::GetEnum<TaskShutdownBehavior,
170 TaskShutdownBehavior::SKIP_ON_SHUTDOWN>(
171 args...)),
172 priority_set_explicitly_(
173 trait_helpers::HasTrait<TaskPriority>(args...)),
174 shutdown_behavior_set_explicitly_(
175 trait_helpers::HasTrait<TaskShutdownBehavior>(args...)),
176 may_block_(trait_helpers::HasTrait<MayBlock>(args...)),
177 with_base_sync_primitives_(
178 trait_helpers::HasTrait<WithBaseSyncPrimitives>(args...)) {}
179
180 constexpr TaskTraits(const TaskTraits& other) = default;
181 TaskTraits& operator=(const TaskTraits& other) = default;
182
183 // TODO(eseckler): Default the comparison operator once C++20 arrives.
184 bool operator==(const TaskTraits& other) const {
185 static_assert(24 == sizeof(TaskTraits),
186 "Update comparison operator when TaskTraits change");
187 return extension_ == other.extension_ && priority_ == other.priority_ &&
188 shutdown_behavior_ == other.shutdown_behavior_ &&
189 priority_set_explicitly_ == other.priority_set_explicitly_ &&
190 shutdown_behavior_set_explicitly_ ==
191 other.shutdown_behavior_set_explicitly_ &&
192 may_block_ == other.may_block_ &&
193 with_base_sync_primitives_ == other.with_base_sync_primitives_;
194 }
195
196 // Sets the priority of tasks with these traits to |priority|.
197 void UpdatePriority(TaskPriority priority) {
198 priority_ = priority;
199 priority_set_explicitly_ = true;
200 }
201
202 // Returns true if the priority was set explicitly.
203 constexpr bool priority_set_explicitly() const {
204 return priority_set_explicitly_;
205 }
206
207 // Returns the priority of tasks with these traits.
208 constexpr TaskPriority priority() const { return priority_; }
209
210 // Returns true if the shutdown behavior was set explicitly.
211 constexpr bool shutdown_behavior_set_explicitly() const {
212 return shutdown_behavior_set_explicitly_;
213 }
214
215 // Returns the shutdown behavior of tasks with these traits.
216 constexpr TaskShutdownBehavior shutdown_behavior() const {
217 return shutdown_behavior_;
218 }
219
220 // Returns true if tasks with these traits may block.
221 constexpr bool may_block() const { return may_block_; }
222
223 // Returns true if tasks with these traits may use base/ sync primitives.
224 constexpr bool with_base_sync_primitives() const {
225 return with_base_sync_primitives_;
226 }
227
228 uint8_t extension_id() const { return extension_.extension_id; }
229
230 // Access the extension data by parsing it into the provided extension type.
231 // See task_traits_extension.h for requirements on the extension type.
232 template <class TaskTraitsExtension>
233 const TaskTraitsExtension GetExtension() const {
234 DCHECK_EQ(TaskTraitsExtension::kExtensionId, extension_.extension_id);
235 return TaskTraitsExtension::Parse(extension_);
236 }
237
238 private:
239 friend PostTaskAndroid;
240
241 // For use by PostTaskAndroid.
242 TaskTraits(bool priority_set_explicitly,
243 TaskPriority priority,
244 bool shutdown_behavior_set_explicitly,
245 TaskShutdownBehavior shutdown_behavior,
246 bool may_block,
247 bool with_base_sync_primitives,
248 TaskTraitsExtensionStorage extension)
249 : extension_(extension),
250 priority_(priority),
251 shutdown_behavior_(shutdown_behavior),
252 priority_set_explicitly_(priority_set_explicitly),
253 shutdown_behavior_set_explicitly_(shutdown_behavior_set_explicitly),
254 may_block_(may_block),
255 with_base_sync_primitives_(with_base_sync_primitives) {
256 static_assert(sizeof(TaskTraits) == 24, "Keep this constructor up to date");
257 }
258
259 // Ordered for packing.
260 TaskTraitsExtensionStorage extension_;
261 TaskPriority priority_;
262 TaskShutdownBehavior shutdown_behavior_;
263 bool priority_set_explicitly_;
264 bool shutdown_behavior_set_explicitly_;
265 bool may_block_;
266 bool with_base_sync_primitives_;
267};
268
269// Returns string literals for the enums defined in this file. These methods
270// should only be used for tracing and debugging.
271BASE_EXPORT const char* TaskPriorityToString(TaskPriority task_priority);
272BASE_EXPORT const char* TaskShutdownBehaviorToString(
273 TaskShutdownBehavior task_priority);
274
275// Stream operators so that the enums defined in this file can be used in
276// DCHECK and EXPECT statements.
277BASE_EXPORT std::ostream& operator<<(std::ostream& os,
278 const TaskPriority& shutdown_behavior);
279BASE_EXPORT std::ostream& operator<<(
280 std::ostream& os,
281 const TaskShutdownBehavior& shutdown_behavior);
282
283} // namespace base
284
285#endif // BASE_TASK_TASK_TRAITS_H_
286