• 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/threading/platform_thread_ref.h"
20 #include "base/time/time.h"
21 #include "build/build_config.h"
22 #include "build/chromeos_buildflags.h"
23 #include "third_party/abseil-cpp/absl/types/optional.h"
24 
25 #if BUILDFLAG(IS_WIN)
26 #include "base/win/windows_types.h"
27 #elif BUILDFLAG(IS_FUCHSIA)
28 #include <zircon/types.h>
29 #elif BUILDFLAG(IS_APPLE)
30 #include <mach/mach_types.h>
31 #elif BUILDFLAG(IS_POSIX)
32 #include <pthread.h>
33 #include <unistd.h>
34 #endif
35 
36 namespace base {
37 
38 // Used for logging. Always an integer value.
39 #if BUILDFLAG(IS_WIN)
40 typedef DWORD PlatformThreadId;
41 #elif BUILDFLAG(IS_FUCHSIA)
42 typedef zx_handle_t PlatformThreadId;
43 #elif BUILDFLAG(IS_APPLE)
44 typedef mach_port_t PlatformThreadId;
45 #elif BUILDFLAG(IS_POSIX)
46 typedef pid_t PlatformThreadId;
47 #endif
48 static_assert(std::is_integral_v<PlatformThreadId>, "Always an integer value.");
49 
50 // Used to operate on threads.
51 class PlatformThreadHandle {
52  public:
53 #if BUILDFLAG(IS_WIN)
54   typedef void* Handle;
55 #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
56   typedef pthread_t Handle;
57 #endif
58 
PlatformThreadHandle()59   constexpr PlatformThreadHandle() : handle_(0) {}
60 
PlatformThreadHandle(Handle handle)61   explicit constexpr PlatformThreadHandle(Handle handle) : handle_(handle) {}
62 
is_equal(const PlatformThreadHandle & other)63   bool is_equal(const PlatformThreadHandle& other) const {
64     return handle_ == other.handle_;
65   }
66 
is_null()67   bool is_null() const {
68     return !handle_;
69   }
70 
platform_handle()71   Handle platform_handle() const {
72     return handle_;
73   }
74 
75  private:
76   Handle handle_;
77 };
78 
79 const PlatformThreadId kInvalidThreadId(0);
80 
81 // Valid values for `thread_type` of Thread::Options, SimpleThread::Options,
82 // and SetCurrentThreadType(), listed in increasing order of importance.
83 //
84 // It is up to each platform-specific implementation what these translate to.
85 // Callers should avoid setting different ThreadTypes on different platforms
86 // (ifdefs) at all cost, instead the platform differences should be encoded in
87 // the platform-specific implementations. Some implementations may treat
88 // adjacent ThreadTypes in this enum as equivalent.
89 //
90 // Reach out to //base/task/OWNERS (scheduler-dev@chromium.org) before changing
91 // thread type assignments in your component, as such decisions affect the whole
92 // of Chrome.
93 //
94 // Refer to PlatformThreadTest.SetCurrentThreadTypeTest in
95 // platform_thread_unittest.cc for the most up-to-date state of each platform's
96 // handling of ThreadType.
97 enum class ThreadType : int {
98   // Suitable for threads that have the least urgency and lowest priority, and
99   // can be interrupted or delayed by other types.
100   kBackground,
101   // Suitable for threads that are less important than normal type, and can be
102   // interrupted or delayed by threads with kDefault type.
103   kUtility,
104   // Suitable for threads that produce user-visible artifacts but aren't
105   // latency sensitive. The underlying platform will try to be economic
106   // in its usage of resources for this thread, if possible.
107   kResourceEfficient,
108   // Default type. The thread priority or quality of service will be set to
109   // platform default. In Chrome, this is suitable for handling user
110   // interactions (input), only display and audio can get a higher priority.
111   kDefault,
112   // Suitable for threads which are critical to compositing the foreground
113   // content.
114   kCompositing,
115   // Suitable for display critical threads.
116   kDisplayCritical,
117   // Suitable for low-latency, glitch-resistant audio.
118   kRealtimeAudio,
119   kMaxValue = kRealtimeAudio,
120 };
121 
122 // Cross-platform mapping of physical thread priorities. Used by tests to verify
123 // the underlying effects of SetCurrentThreadType.
124 enum class ThreadPriorityForTest : int {
125   kBackground,
126   kUtility,
127   kNormal,
128   // The priority obtained via ThreadType::kDisplayCritical (and potentially
129   // other ThreadTypes).
130   kDisplay,
131   kRealtimeAudio,
132   kMaxValue = kRealtimeAudio,
133 };
134 
135 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
136 class ThreadTypeDelegate;
137 #endif
138 
139 // A namespace for low-level thread functions.
140 class BASE_EXPORT PlatformThread {
141  public:
142   // Implement this interface to run code on a background thread.  Your
143   // ThreadMain method will be called on the newly created thread.
144   class BASE_EXPORT Delegate {
145    public:
146 #if BUILDFLAG(IS_APPLE)
147     // The interval at which the thread expects to have work to do. Zero if
148     // unknown. (Example: audio buffer duration for real-time audio.) Is used to
149     // optimize the thread real-time behavior. Is called on the newly created
150     // thread before ThreadMain().
151     virtual TimeDelta GetRealtimePeriod();
152 #endif
153 
154     virtual void ThreadMain() = 0;
155 
156    protected:
157     virtual ~Delegate() = default;
158   };
159 
160   PlatformThread() = delete;
161   PlatformThread(const PlatformThread&) = delete;
162   PlatformThread& operator=(const PlatformThread&) = 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 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
271   // Sets a delegate which handles thread type changes for this process. This
272   // must be externally synchronized with any call to SetCurrentThreadType.
273   static void SetThreadTypeDelegate(ThreadTypeDelegate* delegate);
274 
275   // Toggles a specific thread's type at runtime. This can be used to
276   // change the priority of a thread in a different process and will fail
277   // if the calling process does not have proper permissions. The
278   // SetCurrentThreadType() function above is preferred in favor of
279   // security but on platforms where sandboxed processes are not allowed to
280   // change priority this function exists to allow a non-sandboxed process
281   // to change the priority of sandboxed threads for improved performance.
282   // Warning: Don't use this for a main thread because that will change the
283   // whole thread group's (i.e. process) priority.
284   static void SetThreadType(PlatformThreadId process_id,
285                             PlatformThreadId thread_id,
286                             ThreadType thread_type);
287 #endif
288 
289 #if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_APPLE)
290   // Signals that the feature list has been initialized which allows to check
291   // the feature's value now and initialize state. This prevents race
292   // conditions where the feature is being checked while it is being
293   // initialized, which can cause a crash.
294   static void InitFeaturesPostFieldTrial();
295 #endif
296 
297   // Returns the default thread stack size set by chrome. If we do not
298   // explicitly set default size then returns 0.
299   static size_t GetDefaultThreadStackSize();
300 
301 #if BUILDFLAG(IS_APPLE)
302   // Stores the period value in TLS.
303   static void SetCurrentThreadRealtimePeriodValue(TimeDelta realtime_period);
304 #endif
305 
306   static ThreadPriorityForTest GetCurrentThreadPriorityForTest();
307 };
308 
309 namespace internal {
310 
311 void SetCurrentThreadType(ThreadType thread_type,
312                           MessagePumpType pump_type_hint);
313 
314 void SetCurrentThreadTypeImpl(ThreadType thread_type,
315                               MessagePumpType pump_type_hint);
316 
317 }  // namespace internal
318 
319 }  // namespace base
320 
321 #endif  // BASE_THREADING_PLATFORM_THREAD_H_
322