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 <sched.h> 9 10 #include "base/lazy_instance.h" 11 #include "base/logging.h" 12 #include "base/memory/scoped_ptr.h" 13 #include "base/safe_strerror_posix.h" 14 #include "base/synchronization/waitable_event.h" 15 #include "base/threading/thread_id_name_manager.h" 16 #include "base/threading/thread_restrictions.h" 17 #include "base/tracked_objects.h" 18 19 #if defined(OS_MACOSX) 20 #include <sys/resource.h> 21 #include <algorithm> 22 #endif 23 24 #if defined(OS_LINUX) 25 #include <sys/prctl.h> 26 #include <sys/resource.h> 27 #include <sys/syscall.h> 28 #include <sys/time.h> 29 #include <unistd.h> 30 #endif 31 32 namespace base { 33 34 void InitThreading(); 35 void InitOnThread(); 36 void TerminateOnThread(); 37 size_t GetDefaultThreadStackSize(const pthread_attr_t& attributes); 38 39 namespace { 40 41 struct ThreadParams { 42 ThreadParams() 43 : delegate(NULL), 44 joinable(false), 45 priority(kThreadPriority_Normal), 46 handle(NULL), 47 handle_set(false, false) { 48 } 49 50 PlatformThread::Delegate* delegate; 51 bool joinable; 52 ThreadPriority priority; 53 PlatformThreadHandle* handle; 54 WaitableEvent handle_set; 55 }; 56 57 void* ThreadFunc(void* params) { 58 base::InitOnThread(); 59 ThreadParams* thread_params = static_cast<ThreadParams*>(params); 60 61 PlatformThread::Delegate* delegate = thread_params->delegate; 62 if (!thread_params->joinable) 63 base::ThreadRestrictions::SetSingletonAllowed(false); 64 65 if (thread_params->priority != kThreadPriority_Normal) { 66 PlatformThread::SetThreadPriority(PlatformThread::CurrentHandle(), 67 thread_params->priority); 68 } 69 70 // Stash the id in the handle so the calling thread has a complete 71 // handle, and unblock the parent thread. 72 *(thread_params->handle) = PlatformThreadHandle(pthread_self(), 73 PlatformThread::CurrentId()); 74 thread_params->handle_set.Signal(); 75 76 ThreadIdNameManager::GetInstance()->RegisterThread( 77 PlatformThread::CurrentHandle().platform_handle(), 78 PlatformThread::CurrentId()); 79 80 delegate->ThreadMain(); 81 82 ThreadIdNameManager::GetInstance()->RemoveName( 83 PlatformThread::CurrentHandle().platform_handle(), 84 PlatformThread::CurrentId()); 85 86 base::TerminateOnThread(); 87 return NULL; 88 } 89 90 bool CreateThread(size_t stack_size, bool joinable, 91 PlatformThread::Delegate* delegate, 92 PlatformThreadHandle* thread_handle, 93 ThreadPriority priority) { 94 base::InitThreading(); 95 96 bool success = false; 97 pthread_attr_t attributes; 98 pthread_attr_init(&attributes); 99 100 // Pthreads are joinable by default, so only specify the detached 101 // attribute if the thread should be non-joinable. 102 if (!joinable) { 103 pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_DETACHED); 104 } 105 106 // Get a better default if available. 107 if (stack_size == 0) 108 stack_size = base::GetDefaultThreadStackSize(attributes); 109 110 if (stack_size > 0) 111 pthread_attr_setstacksize(&attributes, stack_size); 112 113 ThreadParams params; 114 params.delegate = delegate; 115 params.joinable = joinable; 116 params.priority = priority; 117 params.handle = thread_handle; 118 119 pthread_t handle; 120 int err = pthread_create(&handle, 121 &attributes, 122 ThreadFunc, 123 ¶ms); 124 success = !err; 125 if (!success) { 126 // Value of |handle| is undefined if pthread_create fails. 127 handle = 0; 128 errno = err; 129 PLOG(ERROR) << "pthread_create"; 130 } 131 132 pthread_attr_destroy(&attributes); 133 134 // Don't let this call complete until the thread id 135 // is set in the handle. 136 if (success) 137 params.handle_set.Wait(); 138 CHECK_EQ(handle, thread_handle->platform_handle()); 139 140 return success; 141 } 142 143 } // namespace 144 145 // static 146 PlatformThreadId PlatformThread::CurrentId() { 147 // Pthreads doesn't have the concept of a thread ID, so we have to reach down 148 // into the kernel. 149 #if defined(OS_MACOSX) 150 return pthread_mach_thread_np(pthread_self()); 151 #elif defined(OS_LINUX) 152 return syscall(__NR_gettid); 153 #elif defined(OS_ANDROID) 154 return gettid(); 155 #elif defined(OS_SOLARIS) || defined(OS_QNX) 156 return pthread_self(); 157 #elif defined(OS_NACL) && defined(__GLIBC__) 158 return pthread_self(); 159 #elif defined(OS_NACL) && !defined(__GLIBC__) 160 // Pointers are 32-bits in NaCl. 161 return reinterpret_cast<int32>(pthread_self()); 162 #elif defined(OS_POSIX) 163 return reinterpret_cast<int64>(pthread_self()); 164 #endif 165 } 166 167 // static 168 PlatformThreadRef PlatformThread::CurrentRef() { 169 return PlatformThreadRef(pthread_self()); 170 } 171 172 // static 173 PlatformThreadHandle PlatformThread::CurrentHandle() { 174 return PlatformThreadHandle(pthread_self(), CurrentId()); 175 } 176 177 // static 178 void PlatformThread::YieldCurrentThread() { 179 sched_yield(); 180 } 181 182 // static 183 void PlatformThread::Sleep(TimeDelta duration) { 184 struct timespec sleep_time, remaining; 185 186 // Break the duration into seconds and nanoseconds. 187 // NOTE: TimeDelta's microseconds are int64s while timespec's 188 // nanoseconds are longs, so this unpacking must prevent overflow. 189 sleep_time.tv_sec = duration.InSeconds(); 190 duration -= TimeDelta::FromSeconds(sleep_time.tv_sec); 191 sleep_time.tv_nsec = duration.InMicroseconds() * 1000; // nanoseconds 192 193 while (nanosleep(&sleep_time, &remaining) == -1 && errno == EINTR) 194 sleep_time = remaining; 195 } 196 197 // static 198 const char* PlatformThread::GetName() { 199 return ThreadIdNameManager::GetInstance()->GetName(CurrentId()); 200 } 201 202 // static 203 bool PlatformThread::Create(size_t stack_size, Delegate* delegate, 204 PlatformThreadHandle* thread_handle) { 205 base::ThreadRestrictions::ScopedAllowWait allow_wait; 206 return CreateThread(stack_size, true /* joinable thread */, 207 delegate, thread_handle, kThreadPriority_Normal); 208 } 209 210 // static 211 bool PlatformThread::CreateWithPriority(size_t stack_size, Delegate* delegate, 212 PlatformThreadHandle* thread_handle, 213 ThreadPriority priority) { 214 base::ThreadRestrictions::ScopedAllowWait allow_wait; 215 return CreateThread(stack_size, true, // joinable thread 216 delegate, thread_handle, priority); 217 } 218 219 // static 220 bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) { 221 PlatformThreadHandle unused; 222 223 base::ThreadRestrictions::ScopedAllowWait allow_wait; 224 bool result = CreateThread(stack_size, false /* non-joinable thread */, 225 delegate, &unused, kThreadPriority_Normal); 226 return result; 227 } 228 229 // static 230 void PlatformThread::Join(PlatformThreadHandle thread_handle) { 231 // Joining another thread may block the current thread for a long time, since 232 // the thread referred to by |thread_handle| may still be running long-lived / 233 // blocking tasks. 234 base::ThreadRestrictions::AssertIOAllowed(); 235 CHECK_EQ(0, pthread_join(thread_handle.handle_, NULL)); 236 } 237 238 } // namespace base 239