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