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