platform_thread.h (15724B)
1 // Copyright 2012 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 // WARNING: You should *NOT* be using this class directly. PlatformThread is 6 // the low-level platform-specific abstraction to the OS's threading interface. 7 // You should instead be using a message-loop driven Thread, see thread.h. 8 9 #ifndef BASE_THREADING_PLATFORM_THREAD_H_ 10 #define BASE_THREADING_PLATFORM_THREAD_H_ 11 12 #include <stddef.h> 13 14 #include <iosfwd> 15 #include <type_traits> 16 17 #include "base/base_export.h" 18 #include "base/message_loop/message_pump_type.h" 19 #include "base/process/process_handle.h" 20 #include "base/sequence_checker_impl.h" 21 #include "base/threading/platform_thread_ref.h" 22 #include "base/time/time.h" 23 #include "base/types/strong_alias.h" 24 #include "build/build_config.h" 25 #include "build/chromeos_buildflags.h" 26 #include "third_party/abseil-cpp/absl/types/optional.h" 27 28 #if BUILDFLAG(IS_WIN) 29 #include "base/win/windows_types.h" 30 #elif BUILDFLAG(IS_FUCHSIA) 31 #include <zircon/types.h> 32 #elif BUILDFLAG(IS_APPLE) 33 #include <mach/mach_types.h> 34 #elif BUILDFLAG(IS_POSIX) 35 #include <pthread.h> 36 #include <unistd.h> 37 #endif 38 39 namespace base { 40 41 // Used for logging. Always an integer value. 42 #if BUILDFLAG(IS_WIN) 43 typedef DWORD PlatformThreadId; 44 #elif BUILDFLAG(IS_FUCHSIA) 45 typedef zx_handle_t PlatformThreadId; 46 #elif BUILDFLAG(IS_APPLE) 47 typedef mach_port_t PlatformThreadId; 48 #elif BUILDFLAG(IS_POSIX) 49 typedef pid_t PlatformThreadId; 50 #endif 51 static_assert(std::is_integral_v<PlatformThreadId>, "Always an integer value."); 52 53 // Used to operate on threads. 54 class PlatformThreadHandle { 55 public: 56 #if BUILDFLAG(IS_WIN) 57 typedef void* Handle; 58 #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA) 59 typedef pthread_t Handle; 60 #endif 61 62 constexpr PlatformThreadHandle() : handle_(0) {} 63 64 explicit constexpr PlatformThreadHandle(Handle handle) : handle_(handle) {} 65 66 bool is_equal(const PlatformThreadHandle& other) const { 67 return handle_ == other.handle_; 68 } 69 70 bool is_null() const { 71 return !handle_; 72 } 73 74 Handle platform_handle() const { 75 return handle_; 76 } 77 78 private: 79 Handle handle_; 80 }; 81 82 const PlatformThreadId kInvalidThreadId(0); 83 84 // Valid values for `thread_type` of Thread::Options, SimpleThread::Options, 85 // and SetCurrentThreadType(), listed in increasing order of importance. 86 // 87 // It is up to each platform-specific implementation what these translate to. 88 // Callers should avoid setting different ThreadTypes on different platforms 89 // (ifdefs) at all cost, instead the platform differences should be encoded in 90 // the platform-specific implementations. Some implementations may treat 91 // adjacent ThreadTypes in this enum as equivalent. 92 // 93 // Reach out to //base/task/OWNERS (scheduler-dev@chromium.org) before changing 94 // thread type assignments in your component, as such decisions affect the whole 95 // of Chrome. 96 // 97 // Refer to PlatformThreadTest.SetCurrentThreadTypeTest in 98 // platform_thread_unittest.cc for the most up-to-date state of each platform's 99 // handling of ThreadType. 100 enum class ThreadType : int { 101 // Suitable for threads that have the least urgency and lowest priority, and 102 // can be interrupted or delayed by other types. 103 kBackground, 104 // Suitable for threads that are less important than normal type, and can be 105 // interrupted or delayed by threads with kDefault type. 106 kUtility, 107 // Suitable for threads that produce user-visible artifacts but aren't 108 // latency sensitive. The underlying platform will try to be economic 109 // in its usage of resources for this thread, if possible. 110 kResourceEfficient, 111 // Default type. The thread priority or quality of service will be set to 112 // platform default. In Chrome, this is suitable for handling user 113 // interactions (input), only display and audio can get a higher priority. 114 kDefault, 115 // Suitable for threads which are critical to compositing the foreground 116 // content. 117 kCompositing, 118 // Suitable for display critical threads. 119 kDisplayCritical, 120 // Suitable for low-latency, glitch-resistant audio. 121 kRealtimeAudio, 122 kMaxValue = kRealtimeAudio, 123 }; 124 125 // Cross-platform mapping of physical thread priorities. Used by tests to verify 126 // the underlying effects of SetCurrentThreadType. 127 enum class ThreadPriorityForTest : int { 128 kBackground, 129 kUtility, 130 kResourceEfficient, 131 kNormal, 132 kCompositing, 133 kDisplay, 134 kRealtimeAudio, 135 kMaxValue = kRealtimeAudio, 136 }; 137 138 // A namespace for low-level thread functions. 139 class BASE_EXPORT PlatformThreadBase { 140 public: 141 // Implement this interface to run code on a background thread. Your 142 // ThreadMain method will be called on the newly created thread. 143 class BASE_EXPORT Delegate { 144 public: 145 virtual void ThreadMain() = 0; 146 147 #if BUILDFLAG(IS_APPLE) 148 // TODO: Move this to the PlatformThreadApple class. 149 // The interval at which the thread expects to have work to do. Zero if 150 // unknown. (Example: audio buffer duration for real-time audio.) Is used to 151 // optimize the thread real-time behavior. Is called on the newly created 152 // thread before ThreadMain(). 153 virtual TimeDelta GetRealtimePeriod(); 154 #endif 155 156 protected: 157 virtual ~Delegate() = default; 158 }; 159 160 PlatformThreadBase() = delete; 161 PlatformThreadBase(const PlatformThreadBase&) = delete; 162 PlatformThreadBase& operator=(const PlatformThreadBase&) = delete; 163 164 // Gets the current thread id, which may be useful for logging purposes. 165 static PlatformThreadId CurrentId(); 166 167 // Gets the current thread reference, which can be used to check if 168 // we're on the right thread quickly. 169 static PlatformThreadRef CurrentRef(); 170 171 // Get the handle representing the current thread. On Windows, this is a 172 // pseudo handle constant which will always represent the thread using it and 173 // hence should not be shared with other threads nor be used to differentiate 174 // the current thread from another. 175 static PlatformThreadHandle CurrentHandle(); 176 177 // Yield the current thread so another thread can be scheduled. 178 // 179 // Note: this is likely not the right call to make in most situations. If this 180 // is part of a spin loop, consider base::Lock, which likely has better tail 181 // latency. Yielding the thread has different effects depending on the 182 // platform, system load, etc., and can result in yielding the CPU for less 183 // than 1us, or many tens of ms. 184 static void YieldCurrentThread(); 185 186 // Sleeps for the specified duration (real-time; ignores time overrides). 187 // Note: The sleep duration may be in base::Time or base::TimeTicks, depending 188 // on platform. If you're looking to use this in unit tests testing delayed 189 // tasks, this will be unreliable - instead, use 190 // base::test::TaskEnvironment with MOCK_TIME mode. 191 static void Sleep(base::TimeDelta duration); 192 193 // Sets the thread name visible to debuggers/tools. This will try to 194 // initialize the context for current thread unless it's a WorkerThread. 195 static void SetName(const std::string& name); 196 197 // Gets the thread name, if previously set by SetName. 198 static const char* GetName(); 199 200 #if !defined(MOZ_SANDBOX) 201 // Creates a new thread. The `stack_size` parameter can be 0 to indicate 202 // that the default stack size should be used. Upon success, 203 // `*thread_handle` will be assigned a handle to the newly created thread, 204 // and `delegate`'s ThreadMain method will be executed on the newly created 205 // thread. 206 // NOTE: When you are done with the thread handle, you must call Join to 207 // release system resources associated with the thread. You must ensure that 208 // the Delegate object outlives the thread. 209 static bool Create(size_t stack_size, 210 Delegate* delegate, 211 PlatformThreadHandle* thread_handle) { 212 return CreateWithType(stack_size, delegate, thread_handle, 213 ThreadType::kDefault); 214 } 215 216 // CreateWithType() does the same thing as Create() except the priority and 217 // possibly the QoS of the thread is set based on `thread_type`. 218 // `pump_type_hint` must be provided if the thread will be using a 219 // MessagePumpForUI or MessagePumpForIO as this affects the application of 220 // `thread_type`. 221 static bool CreateWithType( 222 size_t stack_size, 223 Delegate* delegate, 224 PlatformThreadHandle* thread_handle, 225 ThreadType thread_type, 226 MessagePumpType pump_type_hint = MessagePumpType::DEFAULT); 227 228 // CreateNonJoinable() does the same thing as Create() except the thread 229 // cannot be Join()'d. Therefore, it also does not output a 230 // PlatformThreadHandle. 231 static bool CreateNonJoinable(size_t stack_size, Delegate* delegate); 232 233 // CreateNonJoinableWithType() does the same thing as CreateNonJoinable() 234 // except the type of the thread is set based on `type`. `pump_type_hint` must 235 // be provided if the thread will be using a MessagePumpForUI or 236 // MessagePumpForIO as this affects the application of `thread_type`. 237 static bool CreateNonJoinableWithType( 238 size_t stack_size, 239 Delegate* delegate, 240 ThreadType thread_type, 241 MessagePumpType pump_type_hint = MessagePumpType::DEFAULT); 242 #endif 243 244 // Joins with a thread created via the Create function. This function blocks 245 // the caller until the designated thread exits. This will invalidate 246 // `thread_handle`. 247 static void Join(PlatformThreadHandle thread_handle); 248 249 // Detaches and releases the thread handle. The thread is no longer joinable 250 // and `thread_handle` is invalidated after this call. 251 static void Detach(PlatformThreadHandle thread_handle); 252 253 // Returns true if SetCurrentThreadType() should be able to change the type 254 // of a thread in current process from `from` to `to`. 255 static bool CanChangeThreadType(ThreadType from, ThreadType to); 256 257 // Declares the type of work running on the current thread. This will affect 258 // things like thread priority and thread QoS (Quality of Service) to the best 259 // of the current platform's abilities. 260 static void SetCurrentThreadType(ThreadType thread_type); 261 262 // Get the last `thread_type` set by SetCurrentThreadType, no matter if the 263 // underlying priority successfully changed or not. 264 static ThreadType GetCurrentThreadType(); 265 266 // Returns a realtime period provided by `delegate`. 267 static TimeDelta GetRealtimePeriod(Delegate* delegate); 268 269 // Returns the override of task leeway if any. 270 static absl::optional<TimeDelta> GetThreadLeewayOverride(); 271 272 // Returns the default thread stack size set by chrome. If we do not 273 // explicitly set default size then returns 0. 274 static size_t GetDefaultThreadStackSize(); 275 276 static ThreadPriorityForTest GetCurrentThreadPriorityForTest(); 277 278 protected: 279 static void SetNameCommon(const std::string& name); 280 }; 281 282 #if BUILDFLAG(IS_APPLE) 283 class BASE_EXPORT PlatformThreadApple : public PlatformThreadBase { 284 public: 285 // Stores the period value in TLS. 286 static void SetCurrentThreadRealtimePeriodValue(TimeDelta realtime_period); 287 288 // Signals that the feature list has been initialized which allows to check 289 // the feature's value now and initialize state. This prevents race 290 // conditions where the feature is being checked while it is being 291 // initialized, which can cause a crash. 292 static void InitFeaturesPostFieldTrial(); 293 }; 294 #endif // BUILDFLAG(IS_APPLE) 295 296 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) 297 class ThreadTypeDelegate; 298 using IsViaIPC = base::StrongAlias<class IsViaIPCTag, bool>; 299 300 class BASE_EXPORT PlatformThreadLinux : public PlatformThreadBase { 301 public: 302 static constexpr struct sched_param kRealTimeAudioPrio = {8}; 303 static constexpr struct sched_param kRealTimeDisplayPrio = {6}; 304 305 // Sets a delegate which handles thread type changes for this process. This 306 // must be externally synchronized with any call to SetCurrentThreadType. 307 static void SetThreadTypeDelegate(ThreadTypeDelegate* delegate); 308 309 // Toggles a specific thread's type at runtime. This can be used to 310 // change the priority of a thread in a different process and will fail 311 // if the calling process does not have proper permissions. The 312 // SetCurrentThreadType() function above is preferred in favor of 313 // security but on platforms where sandboxed processes are not allowed to 314 // change priority this function exists to allow a non-sandboxed process 315 // to change the priority of sandboxed threads for improved performance. 316 // Warning: Don't use this for a main thread because that will change the 317 // whole thread group's (i.e. process) priority. 318 static void SetThreadType(PlatformThreadId process_id, 319 PlatformThreadId thread_id, 320 ThreadType thread_type, 321 IsViaIPC via_ipc); 322 323 // For a given thread id and thread type, setup the cpuset and schedtune 324 // CGroups for the thread. 325 static void SetThreadCgroupsForThreadType(PlatformThreadId thread_id, 326 ThreadType thread_type); 327 328 // Determine if thread_id is a background thread by looking up whether 329 // it is in the urgent or non-urgent cpuset 330 static bool IsThreadBackgroundedForTest(PlatformThreadId thread_id); 331 }; 332 #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) 333 334 #if BUILDFLAG(IS_CHROMEOS) 335 336 class BASE_EXPORT PlatformThreadChromeOS : public PlatformThreadLinux { 337 public: 338 // Signals that the feature list has been initialized. Used for preventing 339 // race conditions and crashes, see comments in PlatformThreadApple. 340 static void InitFeaturesPostFieldTrial(); 341 342 // Toggles a specific thread's type at runtime. This is the ChromeOS-specific 343 // version and includes Linux's functionality but does slightly more. See 344 // PlatformThreadLinux's SetThreadType() header comment for Linux details. 345 static void SetThreadType(PlatformThreadId process_id, 346 PlatformThreadId thread_id, 347 ThreadType thread_type, 348 IsViaIPC via_ipc); 349 350 // Returns true if the feature for backgrounding of threads is enabled. 351 static bool IsThreadsBgFeatureEnabled(); 352 353 // Returns true if the feature for setting display threads to RT is enabled. 354 static bool IsDisplayThreadsRtFeatureEnabled(); 355 356 // Set a specific thread as backgrounded. This is called when the process 357 // moves to and from the background and changes have to be made to each of its 358 // thread's scheduling attributes. 359 static void SetThreadBackgrounded(ProcessId process_id, 360 PlatformThreadId thread_id, 361 bool backgrounded); 362 363 // Returns the thread type of a thread given its thread id. 364 static absl::optional<ThreadType> GetThreadTypeFromThreadId( 365 ProcessId process_id, 366 PlatformThreadId thread_id); 367 368 // Returns a SequenceChecker which should be used to verify that all 369 // cross-process priority changes are performed without races. 370 static SequenceCheckerImpl& GetCrossProcessThreadPrioritySequenceChecker(); 371 }; 372 #endif // BUILDFLAG(IS_CHROMEOS) 373 374 // Alias to the correct platform-specific class based on preprocessor directives 375 #if BUILDFLAG(IS_APPLE) 376 using PlatformThread = PlatformThreadApple; 377 #elif BUILDFLAG(IS_CHROMEOS) 378 using PlatformThread = PlatformThreadChromeOS; 379 #elif BUILDFLAG(IS_LINUX) 380 using PlatformThread = PlatformThreadLinux; 381 #else 382 using PlatformThread = PlatformThreadBase; 383 #endif 384 385 #if !defined(MOZ_SANDBOX) 386 namespace internal { 387 388 void SetCurrentThreadType(ThreadType thread_type, 389 MessagePumpType pump_type_hint); 390 391 void SetCurrentThreadTypeImpl(ThreadType thread_type, 392 MessagePumpType pump_type_hint); 393 394 } // namespace internal 395 #endif 396 397 } // namespace base 398 399 #endif // BASE_THREADING_PLATFORM_THREAD_H_