• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_SCHEDULER_TASK_TRAITS_H_
6 #define BASE_TASK_SCHEDULER_TASK_TRAITS_H_
7 
8 #include <stdint.h>
9 
10 #include <iosfwd>
11 #include <type_traits>
12 
13 #include "base/base_export.h"
14 #include "base/task_scheduler/task_traits_details.h"
15 #include "build/build_config.h"
16 
17 namespace base {
18 
19 // Valid priorities supported by the task scheduler. Note: internal algorithms
20 // depend on priorities being expressed as a continuous zero-based list from
21 // lowest to highest priority. Users of this API shouldn't otherwise care about
22 // nor use the underlying values.
23 enum class TaskPriority {
24   // This will always be equal to the lowest priority available.
25   LOWEST = 0,
26   // User won't notice if this task takes an arbitrarily long time to complete.
27   BACKGROUND = LOWEST,
28   // This task affects UI or responsiveness of future user interactions. It is
29   // not an immediate response to a user interaction.
30   // Examples:
31   // - Updating the UI to reflect progress on a long task.
32   // - Loading data that might be shown in the UI after a future user
33   //   interaction.
34   USER_VISIBLE,
35   // This task affects UI immediately after a user interaction.
36   // Example: Generating data shown in the UI immediately after a click.
37   USER_BLOCKING,
38   // This will always be equal to the highest priority available.
39   HIGHEST = USER_BLOCKING,
40 };
41 
42 // Valid shutdown behaviors supported by the task scheduler.
43 enum class TaskShutdownBehavior {
44   // Tasks posted with this mode which have not started executing before
45   // shutdown is initiated will never run. Tasks with this mode running at
46   // shutdown will be ignored (the worker will not be joined).
47   //
48   // This option provides a nice way to post stuff you don't want blocking
49   // shutdown. For example, you might be doing a slow DNS lookup and if it's
50   // blocked on the OS, you may not want to stop shutdown, since the result
51   // doesn't really matter at that point.
52   //
53   // However, you need to be very careful what you do in your callback when you
54   // use this option. Since the thread will continue to run until the OS
55   // terminates the process, the app can be in the process of tearing down when
56   // you're running. This means any singletons or global objects you use may
57   // suddenly become invalid out from under you. For this reason, it's best to
58   // use this only for slow but simple operations like the DNS example.
59   CONTINUE_ON_SHUTDOWN,
60 
61   // Tasks posted with this mode that have not started executing at
62   // shutdown will never run. However, any task that has already begun
63   // executing when shutdown is invoked will be allowed to continue and
64   // will block shutdown until completion.
65   //
66   // Note: Because TaskScheduler::Shutdown() may block while these tasks are
67   // executing, care must be taken to ensure that they do not block on the
68   // thread that called TaskScheduler::Shutdown(), as this may lead to deadlock.
69   SKIP_ON_SHUTDOWN,
70 
71   // Tasks posted with this mode before shutdown is complete will block shutdown
72   // until they're executed. Generally, this should be used only to save
73   // critical user data.
74   //
75   // Note: Tasks with BACKGROUND priority that block shutdown will be promoted
76   // to USER_VISIBLE priority during shutdown.
77   BLOCK_SHUTDOWN,
78 };
79 
80 // Tasks with this trait may block. This includes but is not limited to tasks
81 // that wait on synchronous file I/O operations: read or write a file from disk,
82 // interact with a pipe or a socket, rename or delete a file, enumerate files in
83 // a directory, etc. This trait isn't required for the mere use of locks. For
84 // tasks that block on base/ synchronization primitives, see the
85 // WithBaseSyncPrimitives trait.
86 struct MayBlock {};
87 
88 // DEPRECATED. Use base::ScopedAllowBaseSyncPrimitives(ForTesting) instead.
89 //
90 // Tasks with this trait will pass base::AssertBaseSyncPrimitivesAllowed(), i.e.
91 // will be allowed on the following methods :
92 // - base::WaitableEvent::Wait
93 // - base::ConditionVariable::Wait
94 // - base::PlatformThread::Join
95 // - base::PlatformThread::Sleep
96 // - base::Process::WaitForExit
97 // - base::Process::WaitForExitWithTimeout
98 //
99 // Tasks should generally not use these methods.
100 //
101 // Instead of waiting on a WaitableEvent or a ConditionVariable, put the work
102 // that should happen after the wait in a callback and post that callback from
103 // where the WaitableEvent or ConditionVariable would have been signaled. If
104 // something needs to be scheduled after many tasks have executed, use
105 // base::BarrierClosure.
106 //
107 // On Windows, join processes asynchronously using base::win::ObjectWatcher.
108 //
109 // MayBlock() must be specified in conjunction with this trait if and only if
110 // removing usage of methods listed above in the labeled tasks would still
111 // result in tasks that may block (per MayBlock()'s definition).
112 //
113 // In doubt, consult with //base/task_scheduler/OWNERS.
114 struct WithBaseSyncPrimitives {};
115 
116 // Describes immutable metadata for a single task or a group of tasks.
117 class BASE_EXPORT TaskTraits {
118  private:
119   // ValidTrait ensures TaskTraits' constructor only accepts appropriate types.
120   struct ValidTrait {
ValidTraitValidTrait121     ValidTrait(TaskPriority) {}
ValidTraitValidTrait122     ValidTrait(TaskShutdownBehavior) {}
ValidTraitValidTrait123     ValidTrait(MayBlock) {}
ValidTraitValidTrait124     ValidTrait(WithBaseSyncPrimitives) {}
125   };
126 
127  public:
128   // Invoking this constructor without arguments produces TaskTraits that are
129   // appropriate for tasks that
130   //     (1) don't block (ref. MayBlock() and WithBaseSyncPrimitives()),
131   //     (2) prefer inheriting the current priority to specifying their own, and
132   //     (3) can either block shutdown or be skipped on shutdown
133   //         (TaskScheduler implementation is free to choose a fitting default).
134   //
135   // To get TaskTraits for tasks that require stricter guarantees and/or know
136   // the specific TaskPriority appropriate for them, provide arguments of type
137   // TaskPriority, TaskShutdownBehavior, MayBlock, and/or WithBaseSyncPrimitives
138   // in any order to the constructor.
139   //
140   // E.g.
141   // constexpr base::TaskTraits default_traits = {};
142   // constexpr base::TaskTraits user_visible_traits =
143   //     {base::TaskPriority::USER_VISIBLE};
144   // constexpr base::TaskTraits user_visible_may_block_traits = {
145   //     base::TaskPriority::USER_VISIBLE, base::MayBlock()};
146   // constexpr base::TaskTraits other_user_visible_may_block_traits = {
147   //     base::MayBlock(), base::TaskPriority::USER_VISIBLE};
148   template <class... ArgTypes,
149             class CheckArgumentsAreValid = internal::InitTypes<
150                 decltype(ValidTrait(std::declval<ArgTypes>()))...>>
TaskTraits(ArgTypes...args)151   constexpr TaskTraits(ArgTypes... args)
152       : priority_set_explicitly_(
153             internal::HasArgOfType<TaskPriority, ArgTypes...>::value),
154         priority_(internal::GetValueFromArgList(
155             internal::EnumArgGetter<TaskPriority, TaskPriority::USER_VISIBLE>(),
156             args...)),
157         shutdown_behavior_set_explicitly_(
158             internal::HasArgOfType<TaskShutdownBehavior, ArgTypes...>::value),
159         shutdown_behavior_(internal::GetValueFromArgList(
160             internal::EnumArgGetter<TaskShutdownBehavior,
161                                     TaskShutdownBehavior::SKIP_ON_SHUTDOWN>(),
162             args...)),
163         may_block_(internal::GetValueFromArgList(
164             internal::BooleanArgGetter<MayBlock>(),
165             args...)),
166         with_base_sync_primitives_(internal::GetValueFromArgList(
167             internal::BooleanArgGetter<WithBaseSyncPrimitives>(),
168             args...)) {}
169 
170   constexpr TaskTraits(const TaskTraits& other) = default;
171   TaskTraits& operator=(const TaskTraits& other) = default;
172 
173   // Returns TaskTraits constructed by combining |left| and |right|. If a trait
174   // is specified in both |left| and |right|, the returned TaskTraits will have
175   // the value from |right|.
Override(const TaskTraits & left,const TaskTraits & right)176   static constexpr TaskTraits Override(const TaskTraits& left,
177                                        const TaskTraits& right) {
178     return TaskTraits(left, right);
179   }
180 
181   // Returns true if the priority was set explicitly.
priority_set_explicitly()182   constexpr bool priority_set_explicitly() const {
183     return priority_set_explicitly_;
184   }
185 
186   // Returns the priority of tasks with these traits.
priority()187   constexpr TaskPriority priority() const { return priority_; }
188 
189   // Returns true if the shutdown behavior was set explicitly.
shutdown_behavior_set_explicitly()190   constexpr bool shutdown_behavior_set_explicitly() const {
191     return shutdown_behavior_set_explicitly_;
192   }
193 
194   // Returns the shutdown behavior of tasks with these traits.
shutdown_behavior()195   constexpr TaskShutdownBehavior shutdown_behavior() const {
196     return shutdown_behavior_;
197   }
198 
199   // Returns true if tasks with these traits may block.
may_block()200   constexpr bool may_block() const { return may_block_; }
201 
202   // Returns true if tasks with these traits may use base/ sync primitives.
with_base_sync_primitives()203   constexpr bool with_base_sync_primitives() const {
204     return with_base_sync_primitives_;
205   }
206 
207  private:
TaskTraits(const TaskTraits & left,const TaskTraits & right)208   constexpr TaskTraits(const TaskTraits& left, const TaskTraits& right)
209       : priority_set_explicitly_(left.priority_set_explicitly_ ||
210                                  right.priority_set_explicitly_),
211         priority_(right.priority_set_explicitly_ ? right.priority_
212                                                  : left.priority_),
213         shutdown_behavior_set_explicitly_(
214             left.shutdown_behavior_set_explicitly_ ||
215             right.shutdown_behavior_set_explicitly_),
216         shutdown_behavior_(right.shutdown_behavior_set_explicitly_
217                                ? right.shutdown_behavior_
218                                : left.shutdown_behavior_),
219         may_block_(left.may_block_ || right.may_block_),
220         with_base_sync_primitives_(left.with_base_sync_primitives_ ||
221                                    right.with_base_sync_primitives_) {}
222 
223   bool priority_set_explicitly_;
224   TaskPriority priority_;
225   bool shutdown_behavior_set_explicitly_;
226   TaskShutdownBehavior shutdown_behavior_;
227   bool may_block_;
228   bool with_base_sync_primitives_;
229 };
230 
231 // Returns string literals for the enums defined in this file. These methods
232 // should only be used for tracing and debugging.
233 BASE_EXPORT const char* TaskPriorityToString(TaskPriority task_priority);
234 BASE_EXPORT const char* TaskShutdownBehaviorToString(
235     TaskShutdownBehavior task_priority);
236 
237 // Stream operators so that the enums defined in this file can be used in
238 // DCHECK and EXPECT statements.
239 BASE_EXPORT std::ostream& operator<<(std::ostream& os,
240                                      const TaskPriority& shutdown_behavior);
241 BASE_EXPORT std::ostream& operator<<(
242     std::ostream& os,
243     const TaskShutdownBehavior& shutdown_behavior);
244 
245 }  // namespace base
246 
247 #endif  // BASE_TASK_SCHEDULER_TASK_TRAITS_H_
248