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