1 // Copyright (c) 2012 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 // 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 "base/base_export.h" 15 #include "base/macros.h" 16 #include "base/time/time.h" 17 #include "build/build_config.h" 18 19 #if defined(OS_WIN) 20 #include <windows.h> 21 #elif defined(OS_MACOSX) 22 #include <mach/mach_types.h> 23 #elif defined(OS_POSIX) 24 #include <pthread.h> 25 #include <unistd.h> 26 #endif 27 28 namespace base { 29 30 // Used for logging. Always an integer value. 31 #if defined(OS_WIN) 32 typedef DWORD PlatformThreadId; 33 #elif defined(OS_MACOSX) 34 typedef mach_port_t PlatformThreadId; 35 #elif defined(OS_POSIX) 36 typedef pid_t PlatformThreadId; 37 #endif 38 39 // Used for thread checking and debugging. 40 // Meant to be as fast as possible. 41 // These are produced by PlatformThread::CurrentRef(), and used to later 42 // check if we are on the same thread or not by using ==. These are safe 43 // to copy between threads, but can't be copied to another process as they 44 // have no meaning there. Also, the internal identifier can be re-used 45 // after a thread dies, so a PlatformThreadRef cannot be reliably used 46 // to distinguish a new thread from an old, dead thread. 47 class PlatformThreadRef { 48 public: 49 #if defined(OS_WIN) 50 typedef DWORD RefType; 51 #elif defined(OS_POSIX) 52 typedef pthread_t RefType; 53 #endif PlatformThreadRef()54 PlatformThreadRef() 55 : id_(0) { 56 } 57 PlatformThreadRef(RefType id)58 explicit PlatformThreadRef(RefType id) 59 : id_(id) { 60 } 61 62 bool operator==(PlatformThreadRef other) const { 63 return id_ == other.id_; 64 } 65 66 bool operator!=(PlatformThreadRef other) const { return id_ != other.id_; } 67 is_null()68 bool is_null() const { 69 return id_ == 0; 70 } 71 private: 72 RefType id_; 73 }; 74 75 // Used to operate on threads. 76 class PlatformThreadHandle { 77 public: 78 #if defined(OS_WIN) 79 typedef void* Handle; 80 #elif defined(OS_POSIX) 81 typedef pthread_t Handle; 82 #endif 83 PlatformThreadHandle()84 PlatformThreadHandle() : handle_(0) {} 85 PlatformThreadHandle(Handle handle)86 explicit PlatformThreadHandle(Handle handle) : handle_(handle) {} 87 is_equal(const PlatformThreadHandle & other)88 bool is_equal(const PlatformThreadHandle& other) const { 89 return handle_ == other.handle_; 90 } 91 is_null()92 bool is_null() const { 93 return !handle_; 94 } 95 platform_handle()96 Handle platform_handle() const { 97 return handle_; 98 } 99 100 private: 101 Handle handle_; 102 }; 103 104 const PlatformThreadId kInvalidThreadId(0); 105 106 // Valid values for priority of Thread::Options and SimpleThread::Options, and 107 // SetCurrentThreadPriority(), listed in increasing order of importance. 108 enum class ThreadPriority : int { 109 // Suitable for threads that shouldn't disrupt high priority work. 110 BACKGROUND, 111 // Default priority level. 112 NORMAL, 113 // Suitable for threads which generate data for the display (at ~60Hz). 114 DISPLAY, 115 // Suitable for low-latency, glitch-resistant audio. 116 REALTIME_AUDIO, 117 }; 118 119 // A namespace for low-level thread functions. 120 class BASE_EXPORT PlatformThread { 121 public: 122 // Implement this interface to run code on a background thread. Your 123 // ThreadMain method will be called on the newly created thread. 124 class BASE_EXPORT Delegate { 125 public: 126 virtual void ThreadMain() = 0; 127 128 protected: ~Delegate()129 virtual ~Delegate() {} 130 }; 131 132 // Gets the current thread id, which may be useful for logging purposes. 133 static PlatformThreadId CurrentId(); 134 135 // Gets the current thread reference, which can be used to check if 136 // we're on the right thread quickly. 137 static PlatformThreadRef CurrentRef(); 138 139 // Get the handle representing the current thread. On Windows, this is a 140 // pseudo handle constant which will always represent the thread using it and 141 // hence should not be shared with other threads nor be used to differentiate 142 // the current thread from another. 143 static PlatformThreadHandle CurrentHandle(); 144 145 // Yield the current thread so another thread can be scheduled. 146 static void YieldCurrentThread(); 147 148 // Sleeps for the specified duration. 149 static void Sleep(base::TimeDelta duration); 150 151 // Sets the thread name visible to debuggers/tools. This will try to 152 // initialize the context for current thread unless it's a WorkerThread. 153 static void SetName(const std::string& name); 154 155 // Gets the thread name, if previously set by SetName. 156 static const char* GetName(); 157 158 // Creates a new thread. The |stack_size| parameter can be 0 to indicate 159 // that the default stack size should be used. Upon success, 160 // |*thread_handle| will be assigned a handle to the newly created thread, 161 // and |delegate|'s ThreadMain method will be executed on the newly created 162 // thread. 163 // NOTE: When you are done with the thread handle, you must call Join to 164 // release system resources associated with the thread. You must ensure that 165 // the Delegate object outlives the thread. Create(size_t stack_size,Delegate * delegate,PlatformThreadHandle * thread_handle)166 static bool Create(size_t stack_size, 167 Delegate* delegate, 168 PlatformThreadHandle* thread_handle) { 169 return CreateWithPriority(stack_size, delegate, thread_handle, 170 ThreadPriority::NORMAL); 171 } 172 173 // CreateWithPriority() does the same thing as Create() except the priority of 174 // the thread is set based on |priority|. 175 static bool CreateWithPriority(size_t stack_size, Delegate* delegate, 176 PlatformThreadHandle* thread_handle, 177 ThreadPriority priority); 178 179 // CreateNonJoinable() does the same thing as Create() except the thread 180 // cannot be Join()'d. Therefore, it also does not output a 181 // PlatformThreadHandle. 182 static bool CreateNonJoinable(size_t stack_size, Delegate* delegate); 183 184 // CreateNonJoinableWithPriority() does the same thing as CreateNonJoinable() 185 // except the priority of the thread is set based on |priority|. 186 static bool CreateNonJoinableWithPriority(size_t stack_size, 187 Delegate* delegate, 188 ThreadPriority priority); 189 190 // Joins with a thread created via the Create function. This function blocks 191 // the caller until the designated thread exits. This will invalidate 192 // |thread_handle|. 193 static void Join(PlatformThreadHandle thread_handle); 194 195 // Detaches and releases the thread handle. The thread is no longer joinable 196 // and |thread_handle| is invalidated after this call. 197 static void Detach(PlatformThreadHandle thread_handle); 198 199 // Returns true if SetCurrentThreadPriority() can be used to increase the 200 // priority of the current thread. 201 static bool CanIncreaseCurrentThreadPriority(); 202 203 // Toggles the current thread's priority at runtime. A thread may not be able 204 // to raise its priority back up after lowering it if the process does not 205 // have a proper permission, e.g. CAP_SYS_NICE on Linux. A thread may not be 206 // able to lower its priority back down after raising it to REALTIME_AUDIO. 207 // Since changing other threads' priority is not permitted in favor of 208 // security, this interface is restricted to change only the current thread 209 // priority (https://crbug.com/399473). 210 static void SetCurrentThreadPriority(ThreadPriority priority); 211 212 static ThreadPriority GetCurrentThreadPriority(); 213 214 #if defined(OS_LINUX) 215 // Toggles a specific thread's priority at runtime. This can be used to 216 // change the priority of a thread in a different process and will fail 217 // if the calling process does not have proper permissions. The 218 // SetCurrentThreadPriority() function above is preferred in favor of 219 // security but on platforms where sandboxed processes are not allowed to 220 // change priority this function exists to allow a non-sandboxed process 221 // to change the priority of sandboxed threads for improved performance. 222 // Warning: Don't use this for a main thread because that will change the 223 // whole thread group's (i.e. process) priority. 224 static void SetThreadPriority(PlatformThreadId thread_id, 225 ThreadPriority priority); 226 #endif 227 228 private: 229 DISALLOW_IMPLICIT_CONSTRUCTORS(PlatformThread); 230 }; 231 232 } // namespace base 233 234 #endif // BASE_THREADING_PLATFORM_THREAD_H_ 235