• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
PlatformThreadHandle()62   constexpr PlatformThreadHandle() : handle_(0) {}
63 
PlatformThreadHandle(Handle handle)64   explicit constexpr PlatformThreadHandle(Handle handle) : handle_(handle) {}
65 
is_equal(const PlatformThreadHandle & other)66   bool is_equal(const PlatformThreadHandle& other) const {
67     return handle_ == other.handle_;
68   }
69 
is_null()70   bool is_null() const {
71     return !handle_;
72   }
73 
platform_handle()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   // Creates a new thread.  The `stack_size` parameter can be 0 to indicate
201   // that the default stack size should be used.  Upon success,
202   // `*thread_handle` will be assigned a handle to the newly created thread,
203   // and `delegate`'s ThreadMain method will be executed on the newly created
204   // thread.
205   // NOTE: When you are done with the thread handle, you must call Join to
206   // release system resources associated with the thread.  You must ensure that
207   // the Delegate object outlives the thread.
Create(size_t stack_size,Delegate * delegate,PlatformThreadHandle * thread_handle)208   static bool Create(size_t stack_size,
209                      Delegate* delegate,
210                      PlatformThreadHandle* thread_handle) {
211     return CreateWithType(stack_size, delegate, thread_handle,
212                           ThreadType::kDefault);
213   }
214 
215   // CreateWithType() does the same thing as Create() except the priority and
216   // possibly the QoS of the thread is set based on `thread_type`.
217   // `pump_type_hint` must be provided if the thread will be using a
218   // MessagePumpForUI or MessagePumpForIO as this affects the application of
219   // `thread_type`.
220   static bool CreateWithType(
221       size_t stack_size,
222       Delegate* delegate,
223       PlatformThreadHandle* thread_handle,
224       ThreadType thread_type,
225       MessagePumpType pump_type_hint = MessagePumpType::DEFAULT);
226 
227   // CreateNonJoinable() does the same thing as Create() except the thread
228   // cannot be Join()'d.  Therefore, it also does not output a
229   // PlatformThreadHandle.
230   static bool CreateNonJoinable(size_t stack_size, Delegate* delegate);
231 
232   // CreateNonJoinableWithType() does the same thing as CreateNonJoinable()
233   // except the type of the thread is set based on `type`. `pump_type_hint` must
234   // be provided if the thread will be using a MessagePumpForUI or
235   // MessagePumpForIO as this affects the application of `thread_type`.
236   static bool CreateNonJoinableWithType(
237       size_t stack_size,
238       Delegate* delegate,
239       ThreadType thread_type,
240       MessagePumpType pump_type_hint = MessagePumpType::DEFAULT);
241 
242   // Joins with a thread created via the Create function.  This function blocks
243   // the caller until the designated thread exits.  This will invalidate
244   // `thread_handle`.
245   static void Join(PlatformThreadHandle thread_handle);
246 
247   // Detaches and releases the thread handle. The thread is no longer joinable
248   // and `thread_handle` is invalidated after this call.
249   static void Detach(PlatformThreadHandle thread_handle);
250 
251   // Returns true if SetCurrentThreadType() should be able to change the type
252   // of a thread in current process from `from` to `to`.
253   static bool CanChangeThreadType(ThreadType from, ThreadType to);
254 
255   // Declares the type of work running on the current thread. This will affect
256   // things like thread priority and thread QoS (Quality of Service) to the best
257   // of the current platform's abilities.
258   static void SetCurrentThreadType(ThreadType thread_type);
259 
260   // Get the last `thread_type` set by SetCurrentThreadType, no matter if the
261   // underlying priority successfully changed or not.
262   static ThreadType GetCurrentThreadType();
263 
264   // Returns a realtime period provided by `delegate`.
265   static TimeDelta GetRealtimePeriod(Delegate* delegate);
266 
267   // Returns the override of task leeway if any.
268   static absl::optional<TimeDelta> GetThreadLeewayOverride();
269 
270   // Returns the default thread stack size set by chrome. If we do not
271   // explicitly set default size then returns 0.
272   static size_t GetDefaultThreadStackSize();
273 
274   static ThreadPriorityForTest GetCurrentThreadPriorityForTest();
275 
276   protected:
277   static void SetNameCommon(const std::string& name);
278 };
279 
280 #if BUILDFLAG(IS_APPLE)
281 class BASE_EXPORT PlatformThreadApple : public PlatformThreadBase {
282  public:
283   // Stores the period value in TLS.
284   static void SetCurrentThreadRealtimePeriodValue(TimeDelta realtime_period);
285 
286   // Signals that the feature list has been initialized which allows to check
287   // the feature's value now and initialize state. This prevents race
288   // conditions where the feature is being checked while it is being
289   // initialized, which can cause a crash.
290   static void InitFeaturesPostFieldTrial();
291 };
292 #endif  // BUILDFLAG(IS_APPLE)
293 
294 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
295 class ThreadTypeDelegate;
296 using IsViaIPC = base::StrongAlias<class IsViaIPCTag, bool>;
297 
298 class BASE_EXPORT PlatformThreadLinux : public PlatformThreadBase {
299  public:
300   static constexpr struct sched_param kRealTimeAudioPrio = {8};
301   static constexpr struct sched_param kRealTimeDisplayPrio = {6};
302 
303   // Sets a delegate which handles thread type changes for this process. This
304   // must be externally synchronized with any call to SetCurrentThreadType.
305   static void SetThreadTypeDelegate(ThreadTypeDelegate* delegate);
306 
307   // Toggles a specific thread's type at runtime. This can be used to
308   // change the priority of a thread in a different process and will fail
309   // if the calling process does not have proper permissions. The
310   // SetCurrentThreadType() function above is preferred in favor of
311   // security but on platforms where sandboxed processes are not allowed to
312   // change priority this function exists to allow a non-sandboxed process
313   // to change the priority of sandboxed threads for improved performance.
314   // Warning: Don't use this for a main thread because that will change the
315   // whole thread group's (i.e. process) priority.
316   static void SetThreadType(PlatformThreadId process_id,
317                             PlatformThreadId thread_id,
318                             ThreadType thread_type,
319                             IsViaIPC via_ipc);
320 
321   // For a given thread id and thread type, setup the cpuset and schedtune
322   // CGroups for the thread.
323   static void SetThreadCgroupsForThreadType(PlatformThreadId thread_id,
324                                             ThreadType thread_type);
325 
326   // Determine if thread_id is a background thread by looking up whether
327   // it is in the urgent or non-urgent cpuset
328   static bool IsThreadBackgroundedForTest(PlatformThreadId thread_id);
329 };
330 #endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
331 
332 #if BUILDFLAG(IS_CHROMEOS)
333 
334 class BASE_EXPORT PlatformThreadChromeOS : public PlatformThreadLinux {
335  public:
336   // Signals that the feature list has been initialized. Used for preventing
337   // race conditions and crashes, see comments in PlatformThreadApple.
338   static void InitFeaturesPostFieldTrial();
339 
340   // Toggles a specific thread's type at runtime. This is the ChromeOS-specific
341   // version and includes Linux's functionality but does slightly more. See
342   // PlatformThreadLinux's SetThreadType() header comment for Linux details.
343   static void SetThreadType(PlatformThreadId process_id,
344                             PlatformThreadId thread_id,
345                             ThreadType thread_type,
346                             IsViaIPC via_ipc);
347 
348   // Returns true if the feature for backgrounding of threads is enabled.
349   static bool IsThreadsBgFeatureEnabled();
350 
351   // Returns true if the feature for setting display threads to RT is enabled.
352   static bool IsDisplayThreadsRtFeatureEnabled();
353 
354   // Set a specific thread as backgrounded. This is called when the process
355   // moves to and from the background and changes have to be made to each of its
356   // thread's scheduling attributes.
357   static void SetThreadBackgrounded(ProcessId process_id,
358                                     PlatformThreadId thread_id,
359                                     bool backgrounded);
360 
361   // Returns the thread type of a thread given its thread id.
362   static absl::optional<ThreadType> GetThreadTypeFromThreadId(
363       ProcessId process_id,
364       PlatformThreadId thread_id);
365 
366   // Returns a SequenceChecker which should be used to verify that all
367   // cross-process priority changes are performed without races.
368   static SequenceCheckerImpl& GetCrossProcessThreadPrioritySequenceChecker();
369 };
370 #endif  // BUILDFLAG(IS_CHROMEOS)
371 
372 // Alias to the correct platform-specific class based on preprocessor directives
373 #if BUILDFLAG(IS_APPLE)
374 using PlatformThread = PlatformThreadApple;
375 #elif BUILDFLAG(IS_CHROMEOS)
376 using PlatformThread = PlatformThreadChromeOS;
377 #elif BUILDFLAG(IS_LINUX)
378 using PlatformThread = PlatformThreadLinux;
379 #else
380 using PlatformThread = PlatformThreadBase;
381 #endif
382 
383 namespace internal {
384 
385 void SetCurrentThreadType(ThreadType thread_type,
386                           MessagePumpType pump_type_hint);
387 
388 void SetCurrentThreadTypeImpl(ThreadType thread_type,
389                               MessagePumpType pump_type_hint);
390 
391 }  // namespace internal
392 
393 }  // namespace base
394 
395 #endif  // BASE_THREADING_PLATFORM_THREAD_H_
396