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 // Tasks with this trait will pass base::AssertWaitAllowed(), i.e. will be 89 // allowed on the following methods : 90 // - base::WaitableEvent::Wait 91 // - base::ConditionVariable::Wait 92 // - base::PlatformThread::Join 93 // - base::PlatformThread::Sleep 94 // - base::Process::WaitForExit 95 // - base::Process::WaitForExitWithTimeout 96 // 97 // Tasks should generally not use these methods. 98 // 99 // Instead of waiting on a WaitableEvent or a ConditionVariable, put the work 100 // that should happen after the wait in a callback and post that callback from 101 // where the WaitableEvent or ConditionVariable would have been signaled. If 102 // something needs to be scheduled after many tasks have executed, use 103 // base::BarrierClosure. 104 // 105 // On Windows, join processes asynchronously using base::win::ObjectWatcher. 106 // 107 // MayBlock() must be specified in conjunction with this trait if and only if 108 // removing usage of methods listed above in the labeled tasks would still 109 // result in tasks that may block (per MayBlock()'s definition). 110 // 111 // In doubt, consult with //base/task_scheduler/OWNERS. 112 struct WithBaseSyncPrimitives {}; 113 114 // Describes immutable metadata for a single task or a group of tasks. 115 class BASE_EXPORT TaskTraits { 116 private: 117 // ValidTrait ensures TaskTraits' constructor only accepts appropriate types. 118 struct ValidTrait { ValidTraitValidTrait119 ValidTrait(TaskPriority) {} ValidTraitValidTrait120 ValidTrait(TaskShutdownBehavior) {} ValidTraitValidTrait121 ValidTrait(MayBlock) {} ValidTraitValidTrait122 ValidTrait(WithBaseSyncPrimitives) {} 123 }; 124 125 public: 126 // Invoking this constructor without arguments produces TaskTraits that are 127 // appropriate for tasks that 128 // (1) don't block (ref. MayBlock() and WithBaseSyncPrimitives()), 129 // (2) prefer inheriting the current priority to specifying their own, and 130 // (3) can either block shutdown or be skipped on shutdown 131 // (TaskScheduler implementation is free to choose a fitting default). 132 // 133 // To get TaskTraits for tasks that require stricter guarantees and/or know 134 // the specific TaskPriority appropriate for them, provide arguments of type 135 // TaskPriority, TaskShutdownBehavior, MayBlock, and/or WithBaseSyncPrimitives 136 // in any order to the constructor. 137 // 138 // E.g. 139 // constexpr base::TaskTraits default_traits = {}; 140 // constexpr base::TaskTraits user_visible_traits = 141 // {base::TaskPriority::USER_VISIBLE}; 142 // constexpr base::TaskTraits user_visible_may_block_traits = { 143 // base::TaskPriority::USER_VISIBLE, base::MayBlock()}; 144 // constexpr base::TaskTraits other_user_visible_may_block_traits = { 145 // base::MayBlock(), base::TaskPriority::USER_VISIBLE}; 146 template <class... ArgTypes, 147 class CheckArgumentsAreValid = internal::InitTypes< 148 decltype(ValidTrait(std::declval<ArgTypes>()))...>> TaskTraits(ArgTypes...args)149 constexpr TaskTraits(ArgTypes... args) 150 : priority_set_explicitly_( 151 internal::HasArgOfType<TaskPriority, ArgTypes...>::value), 152 priority_(internal::GetValueFromArgList( 153 internal::EnumArgGetter<TaskPriority, TaskPriority::USER_VISIBLE>(), 154 args...)), 155 shutdown_behavior_set_explicitly_( 156 internal::HasArgOfType<TaskShutdownBehavior, ArgTypes...>::value), 157 shutdown_behavior_(internal::GetValueFromArgList( 158 internal::EnumArgGetter<TaskShutdownBehavior, 159 TaskShutdownBehavior::SKIP_ON_SHUTDOWN>(), 160 args...)), 161 may_block_(internal::GetValueFromArgList( 162 internal::BooleanArgGetter<MayBlock>(), 163 args...)), 164 with_base_sync_primitives_(internal::GetValueFromArgList( 165 internal::BooleanArgGetter<WithBaseSyncPrimitives>(), 166 args...)) {} 167 168 constexpr TaskTraits(const TaskTraits& other) = default; 169 TaskTraits& operator=(const TaskTraits& other) = default; 170 171 // Returns TaskTraits constructed by combining |left| and |right|. If a trait 172 // is specified in both |left| and |right|, the returned TaskTraits will have 173 // the value from |right|. Override(const TaskTraits & left,const TaskTraits & right)174 static constexpr TaskTraits Override(const TaskTraits& left, 175 const TaskTraits& right) { 176 return TaskTraits(left, right); 177 } 178 179 // Returns true if the priority was set explicitly. priority_set_explicitly()180 constexpr bool priority_set_explicitly() const { 181 return priority_set_explicitly_; 182 } 183 184 // Returns the priority of tasks with these traits. priority()185 constexpr TaskPriority priority() const { return priority_; } 186 187 // Returns true if the shutdown behavior was set explicitly. shutdown_behavior_set_explicitly()188 constexpr bool shutdown_behavior_set_explicitly() const { 189 return shutdown_behavior_set_explicitly_; 190 } 191 192 // Returns the shutdown behavior of tasks with these traits. shutdown_behavior()193 constexpr TaskShutdownBehavior shutdown_behavior() const { 194 return shutdown_behavior_; 195 } 196 197 // Returns true if tasks with these traits may block. may_block()198 constexpr bool may_block() const { return may_block_; } 199 200 // Returns true if tasks with these traits may use base/ sync primitives. with_base_sync_primitives()201 constexpr bool with_base_sync_primitives() const { 202 return with_base_sync_primitives_; 203 } 204 205 private: TaskTraits(const TaskTraits & left,const TaskTraits & right)206 constexpr TaskTraits(const TaskTraits& left, const TaskTraits& right) 207 : priority_set_explicitly_(left.priority_set_explicitly_ || 208 right.priority_set_explicitly_), 209 priority_(right.priority_set_explicitly_ ? right.priority_ 210 : left.priority_), 211 shutdown_behavior_set_explicitly_( 212 left.shutdown_behavior_set_explicitly_ || 213 right.shutdown_behavior_set_explicitly_), 214 shutdown_behavior_(right.shutdown_behavior_set_explicitly_ 215 ? right.shutdown_behavior_ 216 : left.shutdown_behavior_), 217 may_block_(left.may_block_ || right.may_block_), 218 with_base_sync_primitives_(left.with_base_sync_primitives_ || 219 right.with_base_sync_primitives_) {} 220 221 bool priority_set_explicitly_; 222 TaskPriority priority_; 223 bool shutdown_behavior_set_explicitly_; 224 TaskShutdownBehavior shutdown_behavior_; 225 bool may_block_; 226 bool with_base_sync_primitives_; 227 }; 228 229 // Returns string literals for the enums defined in this file. These methods 230 // should only be used for tracing and debugging. 231 BASE_EXPORT const char* TaskPriorityToString(TaskPriority task_priority); 232 BASE_EXPORT const char* TaskShutdownBehaviorToString( 233 TaskShutdownBehavior task_priority); 234 235 // Stream operators so that the enums defined in this file can be used in 236 // DCHECK and EXPECT statements. 237 BASE_EXPORT std::ostream& operator<<(std::ostream& os, 238 const TaskPriority& shutdown_behavior); 239 BASE_EXPORT std::ostream& operator<<( 240 std::ostream& os, 241 const TaskShutdownBehavior& shutdown_behavior); 242 243 } // namespace base 244 245 #endif // BASE_TASK_SCHEDULER_TASK_TRAITS_H_ 246