| OLD | NEW |
| (Empty) |
| 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 <sys/resource.h> | |
| 11 #include <sys/time.h> | |
| 12 | |
| 13 #include "base/lazy_instance.h" | |
| 14 #include "base/logging.h" | |
| 15 #include "base/memory/scoped_ptr.h" | |
| 16 #include "base/synchronization/waitable_event.h" | |
| 17 #include "base/threading/platform_thread_internal_posix.h" | |
| 18 #include "base/threading/thread_id_name_manager.h" | |
| 19 #include "base/threading/thread_restrictions.h" | |
| 20 #include "base/tracked_objects.h" | |
| 21 | |
| 22 #if defined(OS_LINUX) | |
| 23 #include <sys/syscall.h> | |
| 24 #elif defined(OS_ANDROID) | |
| 25 #include <sys/types.h> | |
| 26 #endif | |
| 27 | |
| 28 namespace base { | |
| 29 | |
| 30 void InitThreading(); | |
| 31 void InitOnThread(); | |
| 32 void TerminateOnThread(); | |
| 33 size_t GetDefaultThreadStackSize(const pthread_attr_t& attributes); | |
| 34 | |
| 35 namespace { | |
| 36 | |
| 37 struct ThreadParams { | |
| 38 ThreadParams() | |
| 39 : delegate(NULL), | |
| 40 joinable(false), | |
| 41 priority(ThreadPriority::NORMAL), | |
| 42 handle(NULL), | |
| 43 handle_set(false, false) { | |
| 44 } | |
| 45 | |
| 46 PlatformThread::Delegate* delegate; | |
| 47 bool joinable; | |
| 48 ThreadPriority priority; | |
| 49 PlatformThreadHandle* handle; | |
| 50 WaitableEvent handle_set; | |
| 51 }; | |
| 52 | |
| 53 void* ThreadFunc(void* params) { | |
| 54 base::InitOnThread(); | |
| 55 ThreadParams* thread_params = static_cast<ThreadParams*>(params); | |
| 56 | |
| 57 PlatformThread::Delegate* delegate = thread_params->delegate; | |
| 58 if (!thread_params->joinable) | |
| 59 base::ThreadRestrictions::SetSingletonAllowed(false); | |
| 60 | |
| 61 if (thread_params->priority != ThreadPriority::NORMAL) | |
| 62 PlatformThread::SetCurrentThreadPriority(thread_params->priority); | |
| 63 | |
| 64 // Stash the id in the handle so the calling thread has a complete | |
| 65 // handle, and unblock the parent thread. | |
| 66 *(thread_params->handle) = PlatformThreadHandle(pthread_self(), | |
| 67 PlatformThread::CurrentId()); | |
| 68 thread_params->handle_set.Signal(); | |
| 69 | |
| 70 ThreadIdNameManager::GetInstance()->RegisterThread( | |
| 71 PlatformThread::CurrentHandle().platform_handle(), | |
| 72 PlatformThread::CurrentId()); | |
| 73 | |
| 74 delegate->ThreadMain(); | |
| 75 | |
| 76 ThreadIdNameManager::GetInstance()->RemoveName( | |
| 77 PlatformThread::CurrentHandle().platform_handle(), | |
| 78 PlatformThread::CurrentId()); | |
| 79 | |
| 80 base::TerminateOnThread(); | |
| 81 return NULL; | |
| 82 } | |
| 83 | |
| 84 bool CreateThread(size_t stack_size, bool joinable, | |
| 85 PlatformThread::Delegate* delegate, | |
| 86 PlatformThreadHandle* thread_handle, | |
| 87 ThreadPriority priority) { | |
| 88 base::InitThreading(); | |
| 89 | |
| 90 bool success = false; | |
| 91 pthread_attr_t attributes; | |
| 92 pthread_attr_init(&attributes); | |
| 93 | |
| 94 // Pthreads are joinable by default, so only specify the detached | |
| 95 // attribute if the thread should be non-joinable. | |
| 96 if (!joinable) { | |
| 97 pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_DETACHED); | |
| 98 } | |
| 99 | |
| 100 // Get a better default if available. | |
| 101 if (stack_size == 0) | |
| 102 stack_size = base::GetDefaultThreadStackSize(attributes); | |
| 103 | |
| 104 if (stack_size > 0) | |
| 105 pthread_attr_setstacksize(&attributes, stack_size); | |
| 106 | |
| 107 ThreadParams params; | |
| 108 params.delegate = delegate; | |
| 109 params.joinable = joinable; | |
| 110 params.priority = priority; | |
| 111 params.handle = thread_handle; | |
| 112 | |
| 113 pthread_t handle; | |
| 114 int err = pthread_create(&handle, | |
| 115 &attributes, | |
| 116 ThreadFunc, | |
| 117 ¶ms); | |
| 118 success = !err; | |
| 119 if (!success) { | |
| 120 // Value of |handle| is undefined if pthread_create fails. | |
| 121 handle = 0; | |
| 122 errno = err; | |
| 123 PLOG(ERROR) << "pthread_create"; | |
| 124 } | |
| 125 | |
| 126 pthread_attr_destroy(&attributes); | |
| 127 | |
| 128 // Don't let this call complete until the thread id | |
| 129 // is set in the handle. | |
| 130 if (success) | |
| 131 params.handle_set.Wait(); | |
| 132 CHECK_EQ(handle, thread_handle->platform_handle()); | |
| 133 | |
| 134 return success; | |
| 135 } | |
| 136 | |
| 137 } // namespace | |
| 138 | |
| 139 // static | |
| 140 PlatformThreadId PlatformThread::CurrentId() { | |
| 141 // Pthreads doesn't have the concept of a thread ID, so we have to reach down | |
| 142 // into the kernel. | |
| 143 #if defined(OS_MACOSX) | |
| 144 return pthread_mach_thread_np(pthread_self()); | |
| 145 #elif defined(OS_LINUX) | |
| 146 return syscall(__NR_gettid); | |
| 147 #elif defined(OS_ANDROID) | |
| 148 return gettid(); | |
| 149 #elif defined(OS_SOLARIS) || defined(OS_QNX) | |
| 150 return pthread_self(); | |
| 151 #elif defined(OS_NACL) && defined(__GLIBC__) | |
| 152 return pthread_self(); | |
| 153 #elif defined(OS_NACL) && !defined(__GLIBC__) | |
| 154 // Pointers are 32-bits in NaCl. | |
| 155 return reinterpret_cast<int32>(pthread_self()); | |
| 156 #elif defined(OS_POSIX) | |
| 157 return reinterpret_cast<int64>(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(), CurrentId()); | |
| 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::Create(size_t stack_size, Delegate* delegate, | |
| 198 PlatformThreadHandle* thread_handle) { | |
| 199 base::ThreadRestrictions::ScopedAllowWait allow_wait; | |
| 200 return CreateThread(stack_size, true /* joinable thread */, | |
| 201 delegate, thread_handle, ThreadPriority::NORMAL); | |
| 202 } | |
| 203 | |
| 204 // static | |
| 205 bool PlatformThread::CreateWithPriority(size_t stack_size, Delegate* delegate, | |
| 206 PlatformThreadHandle* thread_handle, | |
| 207 ThreadPriority priority) { | |
| 208 base::ThreadRestrictions::ScopedAllowWait allow_wait; | |
| 209 return CreateThread(stack_size, true, // joinable thread | |
| 210 delegate, thread_handle, priority); | |
| 211 } | |
| 212 | |
| 213 // static | |
| 214 bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) { | |
| 215 PlatformThreadHandle unused; | |
| 216 | |
| 217 base::ThreadRestrictions::ScopedAllowWait allow_wait; | |
| 218 bool result = CreateThread(stack_size, false /* non-joinable thread */, | |
| 219 delegate, &unused, ThreadPriority::NORMAL); | |
| 220 return result; | |
| 221 } | |
| 222 | |
| 223 // static | |
| 224 void PlatformThread::Join(PlatformThreadHandle thread_handle) { | |
| 225 // Joining another thread may block the current thread for a long time, since | |
| 226 // the thread referred to by |thread_handle| may still be running long-lived / | |
| 227 // blocking tasks. | |
| 228 base::ThreadRestrictions::AssertIOAllowed(); | |
| 229 CHECK_EQ(0, pthread_join(thread_handle.platform_handle(), NULL)); | |
| 230 } | |
| 231 | |
| 232 // Mac has its own Set/GetCurrentThreadPriority() implementations. | |
| 233 #if !defined(OS_MACOSX) | |
| 234 | |
| 235 // static | |
| 236 void PlatformThread::SetCurrentThreadPriority(ThreadPriority priority) { | |
| 237 #if defined(OS_NACL) | |
| 238 NOTIMPLEMENTED(); | |
| 239 #else | |
| 240 if (internal::SetCurrentThreadPriorityForPlatform(priority)) | |
| 241 return; | |
| 242 | |
| 243 // setpriority(2) should change the whole thread group's (i.e. process) | |
| 244 // priority. However, as stated in the bugs section of | |
| 245 // http://man7.org/linux/man-pages/man2/getpriority.2.html: "under the current | |
| 246 // Linux/NPTL implementation of POSIX threads, the nice value is a per-thread | |
| 247 // attribute". Also, 0 is prefered to the current thread id since it is | |
| 248 // equivalent but makes sandboxing easier (https://crbug.com/399473). | |
| 249 const int nice_setting = internal::ThreadPriorityToNiceValue(priority); | |
| 250 if (setpriority(PRIO_PROCESS, 0, nice_setting)) { | |
| 251 DVPLOG(1) << "Failed to set nice value of thread (" | |
| 252 << PlatformThread::CurrentId() << ") to " << nice_setting; | |
| 253 } | |
| 254 #endif // defined(OS_NACL) | |
| 255 } | |
| 256 | |
| 257 // static | |
| 258 ThreadPriority PlatformThread::GetCurrentThreadPriority() { | |
| 259 #if defined(OS_NACL) | |
| 260 NOTIMPLEMENTED(); | |
| 261 return ThreadPriority::NORMAL; | |
| 262 #else | |
| 263 // Mirrors SetCurrentThreadPriority()'s implementation. | |
| 264 ThreadPriority platform_specific_priority; | |
| 265 if (internal::GetCurrentThreadPriorityForPlatform( | |
| 266 &platform_specific_priority)) { | |
| 267 return platform_specific_priority; | |
| 268 } | |
| 269 | |
| 270 // Need to clear errno before calling getpriority(): | |
| 271 // http://man7.org/linux/man-pages/man2/getpriority.2.html | |
| 272 errno = 0; | |
| 273 int nice_value = getpriority(PRIO_PROCESS, 0); | |
| 274 if (errno != 0) { | |
| 275 DVPLOG(1) << "Failed to get nice value of thread (" | |
| 276 << PlatformThread::CurrentId() << ")"; | |
| 277 return ThreadPriority::NORMAL; | |
| 278 } | |
| 279 | |
| 280 return internal::NiceValueToThreadPriority(nice_value); | |
| 281 #endif // !defined(OS_NACL) | |
| 282 } | |
| 283 | |
| 284 #endif // !defined(OS_MACOSX) | |
| 285 | |
| 286 } // namespace base | |
| OLD | NEW |