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