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