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/check_op.h"
17 #include "base/task/task_traits_extension.h"
18 #include "base/traits_bag.h"
19 #include "build/build_config.h"
20 
21 // TODO(gab): This is backwards, thread_pool.h should include task_traits.h
22 // but it this is necessary to have it in this direction during the migration
23 // from old code that used base::ThreadPool as a trait.
24 #include "base/task/thread_pool.h"
25 
26 namespace base {
27 
28 class PostTaskAndroid;
29 
30 // Valid priorities supported by the task scheduling infrastructure.
31 //
32 // Note: internal algorithms depend on priorities being expressed as a
33 // continuous zero-based list from lowest to highest priority. Users of this API
34 // shouldn't otherwise care about nor use the underlying values.
35 //
36 // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.base.task
37 enum class TaskPriority : uint8_t {
38   // This will always be equal to the lowest priority available.
39   LOWEST = 0,
40   // Best effort tasks will only start running when machine resources are
41   // available. The application may preempt best effort tasks if it expects that
42   // resources will soon be needed by work of higher priority. Dependending on
43   // the ThreadPolicy, best effort tasks may run on a thread that is likely to
44   // be descheduled when higher priority work arrives (in this process or
45   // another).
46   //
47   // Examples:
48   // - Reporting metrics.
49   // - Persisting data to disk.
50   // - Loading data that is required for a potential future user interaction
51   //   (Note: Use CreateUpdateableSequencedTaskRunner() to increase the priority
52   //   when that user interactions happens).
53   BEST_EFFORT = LOWEST,
54 
55   // The result of user visible tasks is visible to the user (in the UI or as a
56   // side-effect on the system) but it is not an immediate response to a user
57   // interaction.
58   //
59   // Examples:
60   // - Updating the UI to reflect progress on a long task.
61   // - Downloading a file requested by the user.
62   // - Loading an image that is displayed in the UI but is non-critical.
63   USER_VISIBLE,
64 
65   // User blocking tasks affects UI immediately after a user interaction.
66   //
67   // Example:
68   // - Loading and rendering a web page after the user clicks a link.
69   // - Sorting suggestions after the user types a character in the omnibox.
70   //
71   // This is the default TaskPriority in order for tasks to run in order by
72   // default and avoid unintended consequences. The only way to get a task to
73   // run at a higher priority than USER_BLOCKING is to coordinate with a
74   // higher-level scheduler (contact scheduler-dev@chromium.org for such use
75   // cases).
76   USER_BLOCKING,
77 
78   // This will always be equal to the highest priority available.
79   HIGHEST = USER_BLOCKING
80 };
81 
82 // Valid shutdown behaviors supported by the thread pool.
83 enum class TaskShutdownBehavior : uint8_t {
84   // Tasks posted with this mode which have not started executing before
85   // shutdown is initiated will never run. Tasks with this mode running at
86   // shutdown will be ignored (the worker will not be joined).
87   //
88   // This option provides a nice way to post stuff you don't want blocking
89   // shutdown. For example, you might be doing a slow DNS lookup and if it's
90   // blocked on the OS, you may not want to stop shutdown, since the result
91   // doesn't really matter at that point.
92   //
93   // However, you need to be very careful what you do in your callback when you
94   // use this option. Since the thread will continue to run until the OS
95   // terminates the process, the app can be in the process of tearing down when
96   // you're running. This means any singletons or global objects you use may
97   // suddenly become invalid out from under you. For this reason, it's best to
98   // use this only for slow but simple operations like the DNS example.
99   CONTINUE_ON_SHUTDOWN,
100 
101   // Tasks posted with this mode that have not started executing at
102   // shutdown will never run. However, any task that has already begun
103   // executing when shutdown is invoked will be allowed to continue and
104   // will block shutdown until completion.
105   //
106   // Note: Because ThreadPoolInstance::Shutdown() may block while these tasks
107   // are executing, care must be taken to ensure that they do not block on the
108   // thread that called ThreadPoolInstance::Shutdown(), as this may lead to
109   // deadlock.
110   SKIP_ON_SHUTDOWN,
111 
112   // Tasks posted with this mode before shutdown is complete will block shutdown
113   // until they're executed. Generally, this should be used only to save
114   // critical user data.
115   //
116   // Note: Background threads will be promoted to normal threads at shutdown
117   // (i.e. TaskPriority::BEST_EFFORT + TaskShutdownBehavior::BLOCK_SHUTDOWN will
118   // resolve without a priority inversion).
119   BLOCK_SHUTDOWN,
120 };
121 
122 // Determines at which thread priority a task may run.
123 //
124 // ThreadPolicy and priority updates
125 // ---------------------------------
126 //
127 //   If the TaskPriority of an UpdateableSequencedTaskRunner is increased while
128 //   one of its tasks is running at background thread priority, the task's
129 //   execution will have to complete at background thread priority (may take a
130 //   long time) before the next task can be scheduled with the new TaskPriority.
131 //   If it is important that priority increases take effect quickly,
132 //   MUST_USE_FOREGROUND should be used to prevent the tasks from running at
133 //   background thread priority. If it is important to minimize impact on the
134 //   rest on the system when the TaskPriority is BEST_EFFORT, PREFER_BACKGROUND
135 //   should be used.
136 //
137 // ThreadPolicy and priority inversions
138 // ------------------------------------
139 //
140 //   A priority inversion occurs when a task running at background thread
141 //   priority is descheduled while holding a resource needed by a thread of
142 //   higher priority. MUST_USE_FOREGROUND can be combined with BEST_EFFORT to
143 //   indicate that a task has a low priority, but shouldn't run at background
144 //   thread priority in order to avoid priority inversions. Please consult with
145 //   //base/task/OWNERS if you suspect a priority inversion.
146 enum class ThreadPolicy : uint8_t {
147   // The task runs on a background priority thread if:
148   // - The TaskPriority is BEST_EFFORT.
149   // - Background thread priority is supported by the platform (see
150   //   environment_config_unittest.cc).
151   // - No extension trait (e.g. BrowserThread) is used.
152   // - ThreadPoolInstance::Shutdown() hadn't been called when the task started running.
153   //       (Remaining TaskShutdownBehavior::BLOCK_SHUTDOWN tasks use foreground
154   //        threads during shutdown regardless of TaskPriority)
155   // Otherwise, it runs on a normal priority thread.
156   // This is the default.
157   PREFER_BACKGROUND,
158 
159   // The task runs at normal thread priority, irrespective of its TaskPriority.
160   MUST_USE_FOREGROUND
161 };
162 
163 // Tasks with this trait may block. This includes but is not limited to tasks
164 // that wait on synchronous file I/O operations: read or write a file from disk,
165 // interact with a pipe or a socket, rename or delete a file, enumerate files in
166 // a directory, etc. This trait isn't required for the mere use of locks. For
167 // tasks that block on base/ synchronization primitives, see the
168 // WithBaseSyncPrimitives trait.
169 struct MayBlock {};
170 
171 // DEPRECATED. Use base::ScopedAllowBaseSyncPrimitives(ForTesting) instead.
172 //
173 // Tasks with this trait will pass base::AssertBaseSyncPrimitivesAllowed(), i.e.
174 // will be allowed on the following methods :
175 // - base::WaitableEvent::Wait
176 // - base::ConditionVariable::Wait
177 // - base::PlatformThread::Join
178 // - base::PlatformThread::Sleep
179 // - base::Process::WaitForExit
180 // - base::Process::WaitForExitWithTimeout
181 //
182 // Tasks should generally not use these methods.
183 //
184 // Instead of waiting on a WaitableEvent or a ConditionVariable, put the work
185 // that should happen after the wait in a callback and post that callback from
186 // where the WaitableEvent or ConditionVariable would have been signaled. If
187 // something needs to be scheduled after many tasks have executed, use
188 // base::BarrierClosure.
189 //
190 // On Windows, join processes asynchronously using base::win::ObjectWatcher.
191 //
192 // MayBlock() must be specified in conjunction with this trait if and only if
193 // removing usage of methods listed above in the labeled tasks would still
194 // result in tasks that may block (per MayBlock()'s definition).
195 //
196 // In doubt, consult with //base/task/OWNERS.
197 struct WithBaseSyncPrimitives {};
198 
199 // Describes metadata for a single task or a group of tasks.
200 class BASE_EXPORT TaskTraits {
201  public:
202   // ValidTrait ensures TaskTraits' constructor only accepts appropriate types.
203   struct ValidTrait {
204     ValidTrait(TaskPriority);
205     ValidTrait(TaskShutdownBehavior);
206     ValidTrait(ThreadPolicy);
207     ValidTrait(MayBlock);
208     ValidTrait(WithBaseSyncPrimitives);
209     ValidTrait(ThreadPool);
210   };
211 
212   // Invoking this constructor without arguments produces default TaskTraits
213   // that are appropriate for tasks that
214   //     (1) don't block (ref. MayBlock() and WithBaseSyncPrimitives()),
215   //     (2) pertain to user-blocking activity,
216   //         (explicitly or implicitly by having an ordering dependency with a
217   //          component that does)
218   //     (3) can either block shutdown or be skipped on shutdown
219   //         (the task recipient is free to choose a fitting default).
220   //
221   // To get TaskTraits for tasks that have more precise traits: provide any
222   // combination of ValidTrait's as arguments to this constructor.
223   //
224   // Note: When posting to well-known threads (e.g. UI/IO), default traits are
225   // almost always what you want unless you know for sure the task being posted
226   // has no explicit/implicit ordering dependency with anything else running at
227   // default (USER_BLOCKING) priority.
228   //
229   // E.g.
230   // constexpr base::TaskTraits default_traits = {};
231   // constexpr base::TaskTraits user_visible_traits = {
232   //     base::TaskPriority::USER_VISIBLE};
233   // constexpr base::TaskTraits user_visible_may_block_traits = {
234   //     base::TaskPriority::USER_VISIBLE, base::MayBlock()
235   // };
236   // constexpr base::TaskTraits other_user_visible_may_block_traits = {
237   //     base::MayBlock(), base::TaskPriority::USER_VISIBLE
238   // };
239   template <class... ArgTypes,
240             class CheckArgumentsAreValid = std::enable_if_t<
241                 trait_helpers::AreValidTraits<ValidTrait, ArgTypes...>::value ||
242                 trait_helpers::AreValidTraitsForExtension<ArgTypes...>::value>>
TaskTraits(ArgTypes...args)243   constexpr TaskTraits(ArgTypes... args)
244       : extension_(trait_helpers::GetTaskTraitsExtension(
245             trait_helpers::AreValidTraits<ValidTrait, ArgTypes...>{},
246             args...)),
247         priority_(
248             trait_helpers::GetEnum<TaskPriority, TaskPriority::USER_BLOCKING>(
249                 args...)),
250         shutdown_behavior_(
251             static_cast<uint8_t>(
252                 trait_helpers::GetEnum<TaskShutdownBehavior,
253                                        TaskShutdownBehavior::SKIP_ON_SHUTDOWN>(
254                     args...)) |
255             (trait_helpers::HasTrait<TaskShutdownBehavior, ArgTypes...>()
256                  ? kIsExplicitFlag
257                  : 0)),
258         thread_policy_(
259             static_cast<uint8_t>(
260                 trait_helpers::GetEnum<ThreadPolicy,
261                                        ThreadPolicy::PREFER_BACKGROUND>(
262                     args...)) |
263             (trait_helpers::HasTrait<ThreadPolicy, ArgTypes...>()
264                  ? kIsExplicitFlag
265                  : 0)),
266         may_block_(trait_helpers::HasTrait<MayBlock, ArgTypes...>()),
267         with_base_sync_primitives_(
268             trait_helpers::HasTrait<WithBaseSyncPrimitives, ArgTypes...>()),
269         use_thread_pool_(trait_helpers::HasTrait<ThreadPool, ArgTypes...>()) {}
270 
271   constexpr TaskTraits(const TaskTraits& other) = default;
272   TaskTraits& operator=(const TaskTraits& other) = default;
273 
274   // TODO(eseckler): Default the comparison operator once C++20 arrives.
275   bool operator==(const TaskTraits& other) const {
276     static_assert(sizeof(TaskTraits) == 15,
277                   "Update comparison operator when TaskTraits change");
278     return extension_ == other.extension_ && priority_ == other.priority_ &&
279            shutdown_behavior_ == other.shutdown_behavior_ &&
280            thread_policy_ == other.thread_policy_ &&
281            may_block_ == other.may_block_ &&
282            with_base_sync_primitives_ == other.with_base_sync_primitives_ &&
283            use_thread_pool_ == other.use_thread_pool_;
284   }
285 
286   // Sets the priority of tasks with these traits to |priority|.
UpdatePriority(TaskPriority priority)287   void UpdatePriority(TaskPriority priority) { priority_ = priority; }
288 
289   // Returns the priority of tasks with these traits.
priority()290   constexpr TaskPriority priority() const { return priority_; }
291 
292   // Returns true if the shutdown behavior was set explicitly.
shutdown_behavior_set_explicitly()293   constexpr bool shutdown_behavior_set_explicitly() const {
294     return shutdown_behavior_ & kIsExplicitFlag;
295   }
296 
297   // Returns the shutdown behavior of tasks with these traits.
shutdown_behavior()298   constexpr TaskShutdownBehavior shutdown_behavior() const {
299     return static_cast<TaskShutdownBehavior>(shutdown_behavior_ &
300                                              ~kIsExplicitFlag);
301   }
302 
303   // Returns true if the thread policy was set explicitly.
thread_policy_set_explicitly()304   constexpr bool thread_policy_set_explicitly() const {
305     return thread_policy_ & kIsExplicitFlag;
306   }
307 
308   // Returns the thread policy of tasks with these traits.
thread_policy()309   constexpr ThreadPolicy thread_policy() const {
310     return static_cast<ThreadPolicy>(thread_policy_ & ~kIsExplicitFlag);
311   }
312 
313   // Returns true if tasks with these traits may block.
may_block()314   constexpr bool may_block() const { return may_block_; }
315 
316   // Returns true if tasks with these traits may use base/ sync primitives.
with_base_sync_primitives()317   constexpr bool with_base_sync_primitives() const {
318     return with_base_sync_primitives_;
319   }
320 
321   // Returns true if tasks with these traits execute on the thread pool.
use_thread_pool()322   constexpr bool use_thread_pool() const { return use_thread_pool_; }
323 
extension_id()324   uint8_t extension_id() const { return extension_.extension_id; }
325 
326   // Access the extension data by parsing it into the provided extension type.
327   // See task_traits_extension.h for requirements on the extension type.
328   template <class TaskTraitsExtension>
GetExtension()329   const TaskTraitsExtension GetExtension() const {
330     DCHECK_EQ(TaskTraitsExtension::kExtensionId, extension_.extension_id);
331     return TaskTraitsExtension::Parse(extension_);
332   }
333 
334  private:
335   friend PostTaskAndroid;
336 
337   // For use by PostTaskAndroid.
TaskTraits(TaskPriority priority,bool may_block,bool use_thread_pool,TaskTraitsExtensionStorage extension)338   TaskTraits(TaskPriority priority,
339              bool may_block,
340              bool use_thread_pool,
341              TaskTraitsExtensionStorage extension)
342       : extension_(extension),
343         priority_(priority),
344         shutdown_behavior_(
345             static_cast<uint8_t>(TaskShutdownBehavior::SKIP_ON_SHUTDOWN)),
346         thread_policy_(static_cast<uint8_t>(ThreadPolicy::PREFER_BACKGROUND)),
347         may_block_(may_block),
348         with_base_sync_primitives_(false),
349         use_thread_pool_(use_thread_pool) {
350     static_assert(sizeof(TaskTraits) == 15, "Keep this constructor up to date");
351 
352     // Java is expected to provide an explicit destination. See TODO in
353     // TaskTraits.java to move towards API-as-a-destination there as well.
354     const bool has_extension =
355         (extension_.extension_id !=
356          TaskTraitsExtensionStorage::kInvalidExtensionId);
357     DCHECK(use_thread_pool_ ^ has_extension)
358         << "Traits must explicitly specify a destination (e.g. ThreadPool or a "
359            "named thread like BrowserThread)";
360   }
361 
362   // This bit is set in |priority_|, |shutdown_behavior_| and |thread_policy_|
363   // when the value was set explicitly.
364   static constexpr uint8_t kIsExplicitFlag = 0x80;
365 
366   // Ordered for packing.
367   TaskTraitsExtensionStorage extension_;
368   TaskPriority priority_;
369   uint8_t shutdown_behavior_;
370   uint8_t thread_policy_;
371   bool may_block_;
372   bool with_base_sync_primitives_;
373   bool use_thread_pool_;
374 };
375 
376 // Returns string literals for the enums defined in this file. These methods
377 // should only be used for tracing and debugging.
378 BASE_EXPORT const char* TaskPriorityToString(TaskPriority task_priority);
379 BASE_EXPORT const char* TaskShutdownBehaviorToString(
380     TaskShutdownBehavior task_priority);
381 
382 // Stream operators so that the enums defined in this file can be used in
383 // DCHECK and EXPECT statements.
384 BASE_EXPORT std::ostream& operator<<(std::ostream& os,
385                                      const TaskPriority& shutdown_behavior);
386 BASE_EXPORT std::ostream& operator<<(
387     std::ostream& os,
388     const TaskShutdownBehavior& shutdown_behavior);
389 
390 }  // namespace base
391 
392 #endif  // BASE_TASK_TASK_TRAITS_H_
393