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 #include "base/threading/platform_thread.h" 6 7 #include <errno.h> 8 #include <pthread.h> 9 #include <sched.h> 10 #include <stddef.h> 11 #include <stdint.h> 12 #include <sys/time.h> 13 #include <sys/types.h> 14 #include <unistd.h> 15 16 #include <memory> 17 18 #include "base/debug/activity_tracker.h" 19 #include "base/lazy_instance.h" 20 #include "base/logging.h" 21 #include "base/threading/platform_thread_internal_posix.h" 22 #include "base/threading/thread_id_name_manager.h" 23 #include "base/threading/thread_restrictions.h" 24 #include "build/build_config.h" 25 26 #if defined(OS_LINUX) 27 #include <sys/syscall.h> 28 #endif 29 30 #if defined(OS_FUCHSIA) 31 #include <zircon/process.h> 32 #else 33 #include <sys/resource.h> 34 #endif 35 36 namespace base { 37 38 void InitThreading(); 39 void TerminateOnThread(); 40 size_t GetDefaultThreadStackSize(const pthread_attr_t& attributes); 41 42 namespace { 43 44 struct ThreadParams { 45 ThreadParams() 46 : delegate(nullptr), joinable(false), priority(ThreadPriority::NORMAL) {} 47 48 PlatformThread::Delegate* delegate; 49 bool joinable; 50 ThreadPriority priority; 51 }; 52 53 void* ThreadFunc(void* params) { 54 PlatformThread::Delegate* delegate = nullptr; 55 56 { 57 std::unique_ptr<ThreadParams> thread_params( 58 static_cast<ThreadParams*>(params)); 59 60 delegate = thread_params->delegate; 61 if (!thread_params->joinable) 62 base::ThreadRestrictions::SetSingletonAllowed(false); 63 64 #if !defined(OS_NACL) 65 // Threads on linux/android may inherit their priority from the thread 66 // where they were created. This explicitly sets the priority of all new 67 // threads. 68 PlatformThread::SetCurrentThreadPriority(thread_params->priority); 69 #endif 70 } 71 72 ThreadIdNameManager::GetInstance()->RegisterThread( 73 PlatformThread::CurrentHandle().platform_handle(), 74 PlatformThread::CurrentId()); 75 76 delegate->ThreadMain(); 77 78 ThreadIdNameManager::GetInstance()->RemoveName( 79 PlatformThread::CurrentHandle().platform_handle(), 80 PlatformThread::CurrentId()); 81 82 base::TerminateOnThread(); 83 return nullptr; 84 } 85 86 bool CreateThread(size_t stack_size, 87 bool joinable, 88 PlatformThread::Delegate* delegate, 89 PlatformThreadHandle* thread_handle, 90 ThreadPriority priority) { 91 DCHECK(thread_handle); 92 base::InitThreading(); 93 94 pthread_attr_t attributes; 95 pthread_attr_init(&attributes); 96 97 // Pthreads are joinable by default, so only specify the detached 98 // attribute if the thread should be non-joinable. 99 if (!joinable) 100 pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_DETACHED); 101 102 // Get a better default if available. 103 if (stack_size == 0) 104 stack_size = base::GetDefaultThreadStackSize(attributes); 105 106 if (stack_size > 0) 107 pthread_attr_setstacksize(&attributes, stack_size); 108 109 std::unique_ptr<ThreadParams> params(new ThreadParams); 110 params->delegate = delegate; 111 params->joinable = joinable; 112 params->priority = priority; 113 114 pthread_t handle; 115 int err = pthread_create(&handle, &attributes, ThreadFunc, params.get()); 116 bool success = !err; 117 if (success) { 118 // ThreadParams should be deleted on the created thread after used. 119 ignore_result(params.release()); 120 } else { 121 // Value of |handle| is undefined if pthread_create fails. 122 handle = 0; 123 errno = err; 124 PLOG(ERROR) << "pthread_create"; 125 } 126 *thread_handle = PlatformThreadHandle(handle); 127 128 pthread_attr_destroy(&attributes); 129 130 return success; 131 } 132 133 } // namespace 134 135 // static 136 PlatformThreadId PlatformThread::CurrentId() { 137 // Pthreads doesn't have the concept of a thread ID, so we have to reach down 138 // into the kernel. 139 #if defined(OS_MACOSX) 140 return pthread_mach_thread_np(pthread_self()); 141 #elif defined(OS_LINUX) 142 return syscall(__NR_gettid); 143 #elif defined(OS_ANDROID) 144 return gettid(); 145 #elif defined(OS_FUCHSIA) 146 return zx_thread_self(); 147 #elif defined(OS_SOLARIS) || defined(OS_QNX) 148 return pthread_self(); 149 #elif defined(OS_NACL) && defined(__GLIBC__) 150 return pthread_self(); 151 #elif defined(OS_NACL) && !defined(__GLIBC__) 152 // Pointers are 32-bits in NaCl. 153 return reinterpret_cast<int32_t>(pthread_self()); 154 #elif defined(OS_POSIX) && defined(OS_AIX) 155 return pthread_self(); 156 #elif defined(OS_POSIX) && !defined(OS_AIX) 157 return reinterpret_cast<int64_t>(pthread_self()); 158 #endif 159 } 160 161 // static 162 PlatformThreadRef PlatformThread::CurrentRef() { 163 return PlatformThreadRef(pthread_self()); 164 } 165 166 // static 167 PlatformThreadHandle PlatformThread::CurrentHandle() { 168 return PlatformThreadHandle(pthread_self()); 169 } 170 171 // static 172 void PlatformThread::YieldCurrentThread() { 173 sched_yield(); 174 } 175 176 // static 177 void PlatformThread::Sleep(TimeDelta duration) { 178 struct timespec sleep_time, remaining; 179 180 // Break the duration into seconds and nanoseconds. 181 // NOTE: TimeDelta's microseconds are int64s while timespec's 182 // nanoseconds are longs, so this unpacking must prevent overflow. 183 sleep_time.tv_sec = duration.InSeconds(); 184 duration -= TimeDelta::FromSeconds(sleep_time.tv_sec); 185 sleep_time.tv_nsec = duration.InMicroseconds() * 1000; // nanoseconds 186 187 while (nanosleep(&sleep_time, &remaining) == -1 && errno == EINTR) 188 sleep_time = remaining; 189 } 190 191 // static 192 const char* PlatformThread::GetName() { 193 return ThreadIdNameManager::GetInstance()->GetName(CurrentId()); 194 } 195 196 // static 197 bool PlatformThread::CreateWithPriority(size_t stack_size, Delegate* delegate, 198 PlatformThreadHandle* thread_handle, 199 ThreadPriority priority) { 200 return CreateThread(stack_size, true /* joinable thread */, delegate, 201 thread_handle, priority); 202 } 203 204 // static 205 bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) { 206 return CreateNonJoinableWithPriority(stack_size, delegate, 207 ThreadPriority::NORMAL); 208 } 209 210 // static 211 bool PlatformThread::CreateNonJoinableWithPriority(size_t stack_size, 212 Delegate* delegate, 213 ThreadPriority priority) { 214 PlatformThreadHandle unused; 215 216 bool result = CreateThread(stack_size, false /* non-joinable thread */, 217 delegate, &unused, priority); 218 return result; 219 } 220 221 // static 222 void PlatformThread::Join(PlatformThreadHandle thread_handle) { 223 // Record the event that this thread is blocking upon (for hang diagnosis). 224 base::debug::ScopedThreadJoinActivity thread_activity(&thread_handle); 225 226 // Joining another thread may block the current thread for a long time, since 227 // the thread referred to by |thread_handle| may still be running long-lived / 228 // blocking tasks. 229 AssertBlockingAllowed(); 230 CHECK_EQ(0, pthread_join(thread_handle.platform_handle(), nullptr)); 231 } 232 233 // static 234 void PlatformThread::Detach(PlatformThreadHandle thread_handle) { 235 CHECK_EQ(0, pthread_detach(thread_handle.platform_handle())); 236 } 237 238 // Mac and Fuchsia have their own Set/GetCurrentThreadPriority() 239 // implementations. 240 #if !defined(OS_MACOSX) && !defined(OS_FUCHSIA) 241 242 // static 243 bool PlatformThread::CanIncreaseCurrentThreadPriority() { 244 #if defined(OS_NACL) 245 return false; 246 #else 247 // Only root can raise thread priority on POSIX environment. On Linux, users 248 // who have CAP_SYS_NICE permission also can raise the thread priority, but 249 // libcap.so would be needed to check the capability. 250 return geteuid() == 0; 251 #endif // defined(OS_NACL) 252 } 253 254 // static 255 void PlatformThread::SetCurrentThreadPriority(ThreadPriority priority) { 256 #if defined(OS_NACL) 257 NOTIMPLEMENTED(); 258 #else 259 if (internal::SetCurrentThreadPriorityForPlatform(priority)) 260 return; 261 262 // setpriority(2) should change the whole thread group's (i.e. process) 263 // priority. However, as stated in the bugs section of 264 // http://man7.org/linux/man-pages/man2/getpriority.2.html: "under the current 265 // Linux/NPTL implementation of POSIX threads, the nice value is a per-thread 266 // attribute". Also, 0 is prefered to the current thread id since it is 267 // equivalent but makes sandboxing easier (https://crbug.com/399473). 268 const int nice_setting = internal::ThreadPriorityToNiceValue(priority); 269 if (setpriority(PRIO_PROCESS, 0, nice_setting)) { 270 DVPLOG(1) << "Failed to set nice value of thread (" 271 << PlatformThread::CurrentId() << ") to " << nice_setting; 272 } 273 #endif // defined(OS_NACL) 274 } 275 276 // static 277 ThreadPriority PlatformThread::GetCurrentThreadPriority() { 278 #if defined(OS_NACL) 279 NOTIMPLEMENTED(); 280 return ThreadPriority::NORMAL; 281 #else 282 // Mirrors SetCurrentThreadPriority()'s implementation. 283 ThreadPriority platform_specific_priority; 284 if (internal::GetCurrentThreadPriorityForPlatform( 285 &platform_specific_priority)) { 286 return platform_specific_priority; 287 } 288 289 // Need to clear errno before calling getpriority(): 290 // http://man7.org/linux/man-pages/man2/getpriority.2.html 291 errno = 0; 292 int nice_value = getpriority(PRIO_PROCESS, 0); 293 if (errno != 0) { 294 DVPLOG(1) << "Failed to get nice value of thread (" 295 << PlatformThread::CurrentId() << ")"; 296 return ThreadPriority::NORMAL; 297 } 298 299 return internal::NiceValueToThreadPriority(nice_value); 300 #endif // !defined(OS_NACL) 301 } 302 303 #endif // !defined(OS_MACOSX) && !defined(OS_FUCHSIA) 304 305 } // namespace base 306