Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/threading/platform_thread.h" | 5 #include "base/threading/platform_thread.h" |
| 6 | 6 |
| 7 #include <errno.h> | 7 #include <errno.h> |
| 8 #include <sched.h> | 8 #include <sched.h> |
| 9 | 9 |
| 10 #include "base/lazy_instance.h" | 10 #include "base/lazy_instance.h" |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 21 #endif | 21 #endif |
| 22 | 22 |
| 23 #if defined(OS_LINUX) | 23 #if defined(OS_LINUX) |
| 24 #include <sys/prctl.h> | 24 #include <sys/prctl.h> |
| 25 #include <sys/resource.h> | 25 #include <sys/resource.h> |
| 26 #include <sys/syscall.h> | 26 #include <sys/syscall.h> |
| 27 #include <sys/time.h> | 27 #include <sys/time.h> |
| 28 #include <unistd.h> | 28 #include <unistd.h> |
| 29 #endif | 29 #endif |
| 30 | 30 |
| 31 #if defined(OS_ANDROID) | |
| 32 #include <sys/resource.h> | |
| 33 #include "base/android/thread_utils.h" | |
| 34 #include "jni/ThreadUtils_jni.h" | |
| 35 #endif | |
| 36 | |
| 37 // TODO(bbudge) Use time.h when NaCl toolchain supports _POSIX_TIMERS | 31 // TODO(bbudge) Use time.h when NaCl toolchain supports _POSIX_TIMERS |
| 38 #if defined(OS_NACL) | 32 #if defined(OS_NACL) |
| 39 #include <sys/nacl_syscalls.h> | 33 #include <sys/nacl_syscalls.h> |
| 40 #endif | 34 #endif |
| 41 | 35 |
| 42 namespace base { | 36 namespace base { |
| 43 | 37 |
| 44 #if defined(OS_MACOSX) | |
| 45 void InitThreading(); | 38 void InitThreading(); |
| 46 #endif | 39 void InitOnThread(); |
| 40 void TerminateOnThread(); | |
| 41 size_t GetDefaultThreadStackSize(const pthread_attr_t& attributes); | |
| 47 | 42 |
| 48 namespace { | 43 namespace { |
| 49 | 44 |
| 50 struct ThreadParams { | 45 struct ThreadParams { |
| 51 PlatformThread::Delegate* delegate; | 46 PlatformThread::Delegate* delegate; |
| 52 bool joinable; | 47 bool joinable; |
| 53 ThreadPriority priority; | 48 ThreadPriority priority; |
| 54 }; | 49 }; |
| 55 | 50 |
| 56 void SetCurrentThreadPriority(ThreadPriority priority) { | |
| 57 #if defined(OS_LINUX) || defined(OS_ANDROID) | |
| 58 switch (priority) { | |
| 59 case kThreadPriority_Normal: | |
| 60 NOTREACHED() << "Don't reset priority as not all processes can."; | |
| 61 break; | |
| 62 case kThreadPriority_RealtimeAudio: | |
| 63 #if defined(OS_LINUX) | |
| 64 const int kNiceSetting = -10; | |
| 65 // Linux isn't posix compliant with setpriority(2), it will set a thread | |
| 66 // priority if it is passed a tid, not affecting the rest of the threads | |
| 67 // in the process. Setting this priority will only succeed if the user | |
| 68 // has been granted permission to adjust nice values on the system. | |
| 69 if (setpriority(PRIO_PROCESS, PlatformThread::CurrentId(), kNiceSetting)) | |
| 70 DVLOG(1) << "Failed to set nice value of thread to " << kNiceSetting; | |
| 71 #elif defined(OS_ANDROID) | |
| 72 JNIEnv* env = base::android::AttachCurrentThread(); | |
| 73 Java_ThreadUtils_setThreadPriorityAudio(env, PlatformThread::CurrentId()); | |
| 74 #endif // defined(OS_LINUX) | |
| 75 break; | |
| 76 } | |
| 77 #else // !defined(OS_LINUX) && !defined(OS_ANDROID) | |
| 78 PlatformThread::SetThreadPriority(pthread_self(), priority); | |
| 79 #endif | |
| 80 } | |
| 81 | |
| 82 void* ThreadFunc(void* params) { | 51 void* ThreadFunc(void* params) { |
| 83 #if defined(OS_ANDROID) | 52 base::InitOnThread(); |
| 84 // Threads on linux/android may inherit their priority from the thread | |
| 85 // where they were created. This sets all threads to the default. | |
| 86 // TODO(epenner): Move thread priorities to base. (crbug.com/170549) | |
| 87 if (setpriority(PRIO_PROCESS, PlatformThread::CurrentId(), 0)) | |
| 88 DVLOG(1) << "Failed to reset initial thread nice value to zero."; | |
| 89 #endif | |
| 90 ThreadParams* thread_params = static_cast<ThreadParams*>(params); | 53 ThreadParams* thread_params = static_cast<ThreadParams*>(params); |
| 91 PlatformThread::Delegate* delegate = thread_params->delegate; | 54 PlatformThread::Delegate* delegate = thread_params->delegate; |
| 92 if (!thread_params->joinable) | 55 if (!thread_params->joinable) |
| 93 base::ThreadRestrictions::SetSingletonAllowed(false); | 56 base::ThreadRestrictions::SetSingletonAllowed(false); |
| 94 | 57 |
| 95 // If there is a non-default priority for this thread, set it now. | 58 if (thread_params->priority != kThreadPriority_Normal) { |
| 96 if (thread_params->priority != kThreadPriority_Normal) | 59 PlatformThread::SetThreadPriority(pthread_self(), |
| 97 SetCurrentThreadPriority(thread_params->priority); | 60 PlatformThread::CurrentId(), |
| 61 thread_params->priority); | |
| 62 } | |
| 98 | 63 |
| 99 delete thread_params; | 64 delete thread_params; |
| 100 delegate->ThreadMain(); | 65 delegate->ThreadMain(); |
| 101 #if defined(OS_ANDROID) | 66 base::TerminateOnThread(); |
| 102 base::android::DetachFromVM(); | |
| 103 #endif | |
| 104 return NULL; | 67 return NULL; |
| 105 } | 68 } |
| 106 | 69 |
| 107 bool CreateThread(size_t stack_size, bool joinable, | 70 bool CreateThread(size_t stack_size, bool joinable, |
| 108 PlatformThread::Delegate* delegate, | 71 PlatformThread::Delegate* delegate, |
| 109 PlatformThreadHandle* thread_handle, | 72 PlatformThreadHandle* thread_handle, |
| 110 ThreadPriority priority) { | 73 ThreadPriority priority) { |
| 111 #if defined(OS_MACOSX) | |
| 112 base::InitThreading(); | 74 base::InitThreading(); |
| 113 #endif // OS_MACOSX | |
| 114 | 75 |
| 115 bool success = false; | 76 bool success = false; |
| 116 pthread_attr_t attributes; | 77 pthread_attr_t attributes; |
| 117 pthread_attr_init(&attributes); | 78 pthread_attr_init(&attributes); |
| 118 | 79 |
| 119 // Pthreads are joinable by default, so only specify the detached attribute if | 80 // Pthreads are joinable by default, so only specify the detached attribute if |
| 120 // the thread should be non-joinable. | 81 // the thread should be non-joinable. |
| 121 if (!joinable) { | 82 if (!joinable) { |
| 122 pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_DETACHED); | 83 pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_DETACHED); |
| 123 } | 84 } |
| 124 | 85 |
| 125 #if defined(OS_MACOSX) && !defined(OS_IOS) | 86 // Get a better default if available. |
| 126 // The Mac OS X default for a pthread stack size is 512kB. | 87 if (stack_size == 0) |
| 127 // Libc-594.1.4/pthreads/pthread.c's pthread_attr_init uses | 88 stack_size = base::GetDefaultThreadStackSize(attributes); |
| 128 // DEFAULT_STACK_SIZE for this purpose. | |
| 129 // | |
| 130 // 512kB isn't quite generous enough for some deeply recursive threads that | |
| 131 // otherwise request the default stack size by specifying 0. Here, adopt | |
| 132 // glibc's behavior as on Linux, which is to use the current stack size | |
| 133 // limit (ulimit -s) as the default stack size. See | |
| 134 // glibc-2.11.1/nptl/nptl-init.c's __pthread_initialize_minimal_internal. To | |
| 135 // avoid setting the limit below the Mac OS X default or the minimum usable | |
| 136 // stack size, these values are also considered. If any of these values | |
| 137 // can't be determined, or if stack size is unlimited (ulimit -s unlimited), | |
| 138 // stack_size is left at 0 to get the system default. | |
| 139 // | |
| 140 // Mac OS X normally only applies ulimit -s to the main thread stack. On | |
| 141 // contemporary OS X and Linux systems alike, this value is generally 8MB | |
| 142 // or in that neighborhood. | |
| 143 if (stack_size == 0) { | |
| 144 size_t default_stack_size; | |
| 145 struct rlimit stack_rlimit; | |
| 146 if (pthread_attr_getstacksize(&attributes, &default_stack_size) == 0 && | |
| 147 getrlimit(RLIMIT_STACK, &stack_rlimit) == 0 && | |
| 148 stack_rlimit.rlim_cur != RLIM_INFINITY) { | |
| 149 stack_size = std::max(std::max(default_stack_size, | |
| 150 static_cast<size_t>(PTHREAD_STACK_MIN)), | |
| 151 static_cast<size_t>(stack_rlimit.rlim_cur)); | |
| 152 } | |
| 153 } | |
| 154 #endif // OS_MACOSX && !OS_IOS | |
| 155 | 89 |
| 156 if (stack_size > 0) | 90 if (stack_size > 0) |
| 157 pthread_attr_setstacksize(&attributes, stack_size); | 91 pthread_attr_setstacksize(&attributes, stack_size); |
| 158 | 92 |
| 159 ThreadParams* params = new ThreadParams; | 93 ThreadParams* params = new ThreadParams; |
| 160 params->delegate = delegate; | 94 params->delegate = delegate; |
| 161 params->joinable = joinable; | 95 params->joinable = joinable; |
| 162 params->priority = priority; | 96 params->priority = priority; |
| 163 | 97 |
| 164 int err = pthread_create(thread_handle, &attributes, ThreadFunc, params); | 98 int err = pthread_create(thread_handle, &attributes, ThreadFunc, params); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 211 // NOTE: TimeDelta's microseconds are int64s while timespec's | 145 // NOTE: TimeDelta's microseconds are int64s while timespec's |
| 212 // nanoseconds are longs, so this unpacking must prevent overflow. | 146 // nanoseconds are longs, so this unpacking must prevent overflow. |
| 213 sleep_time.tv_sec = duration.InSeconds(); | 147 sleep_time.tv_sec = duration.InSeconds(); |
| 214 duration -= TimeDelta::FromSeconds(sleep_time.tv_sec); | 148 duration -= TimeDelta::FromSeconds(sleep_time.tv_sec); |
| 215 sleep_time.tv_nsec = duration.InMicroseconds() * 1000; // nanoseconds | 149 sleep_time.tv_nsec = duration.InMicroseconds() * 1000; // nanoseconds |
| 216 | 150 |
| 217 while (nanosleep(&sleep_time, &remaining) == -1 && errno == EINTR) | 151 while (nanosleep(&sleep_time, &remaining) == -1 && errno == EINTR) |
| 218 sleep_time = remaining; | 152 sleep_time = remaining; |
| 219 } | 153 } |
| 220 | 154 |
| 221 #if defined(OS_LINUX) | |
| 222 // static | |
| 223 void PlatformThread::SetName(const char* name) { | |
| 224 ThreadIdNameManager::GetInstance()->SetName(CurrentId(), name); | |
| 225 tracked_objects::ThreadData::InitializeThreadContext(name); | |
| 226 | |
| 227 // On linux we can get the thread names to show up in the debugger by setting | |
| 228 // the process name for the LWP. We don't want to do this for the main | |
| 229 // thread because that would rename the process, causing tools like killall | |
| 230 // to stop working. | |
| 231 if (PlatformThread::CurrentId() == getpid()) | |
| 232 return; | |
| 233 | |
| 234 // http://0pointer.de/blog/projects/name-your-threads.html | |
| 235 // Set the name for the LWP (which gets truncated to 15 characters). | |
| 236 // Note that glibc also has a 'pthread_setname_np' api, but it may not be | |
| 237 // available everywhere and it's only benefit over using prctl directly is | |
| 238 // that it can set the name of threads other than the current thread. | |
| 239 int err = prctl(PR_SET_NAME, name); | |
| 240 // We expect EPERM failures in sandboxed processes, just ignore those. | |
| 241 if (err < 0 && errno != EPERM) | |
| 242 DPLOG(ERROR) << "prctl(PR_SET_NAME)"; | |
| 243 } | |
| 244 #elif defined(OS_MACOSX) | |
| 245 // Mac is implemented in platform_thread_mac.mm. | |
| 246 #else | |
| 247 // static | |
| 248 void PlatformThread::SetName(const char* name) { | |
| 249 ThreadIdNameManager::GetInstance()->SetName(CurrentId(), name); | |
| 250 tracked_objects::ThreadData::InitializeThreadContext(name); | |
| 251 | |
| 252 // (This should be relatively simple to implement for the BSDs; I | |
| 253 // just don't have one handy to test the code on.) | |
| 254 } | |
| 255 #endif // defined(OS_LINUX) | |
| 256 | |
| 257 // static | 155 // static |
| 258 const char* PlatformThread::GetName() { | 156 const char* PlatformThread::GetName() { |
| 259 return ThreadIdNameManager::GetInstance()->GetName(CurrentId()); | 157 return ThreadIdNameManager::GetInstance()->GetName(CurrentId()); |
| 260 } | 158 } |
| 261 | 159 |
| 262 // static | 160 // static |
| 263 bool PlatformThread::Create(size_t stack_size, Delegate* delegate, | 161 bool PlatformThread::Create(size_t stack_size, Delegate* delegate, |
| 264 PlatformThreadHandle* thread_handle) { | 162 PlatformThreadHandle* thread_handle) { |
| 265 return CreateThread(stack_size, true /* joinable thread */, | 163 return CreateThread(stack_size, true /* joinable thread */, |
| 266 delegate, thread_handle, kThreadPriority_Normal); | 164 delegate, thread_handle, kThreadPriority_Normal); |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 285 | 183 |
| 286 // static | 184 // static |
| 287 void PlatformThread::Join(PlatformThreadHandle thread_handle) { | 185 void PlatformThread::Join(PlatformThreadHandle thread_handle) { |
| 288 // Joining another thread may block the current thread for a long time, since | 186 // Joining another thread may block the current thread for a long time, since |
| 289 // the thread referred to by |thread_handle| may still be running long-lived / | 187 // the thread referred to by |thread_handle| may still be running long-lived / |
| 290 // blocking tasks. | 188 // blocking tasks. |
| 291 base::ThreadRestrictions::AssertIOAllowed(); | 189 base::ThreadRestrictions::AssertIOAllowed(); |
| 292 pthread_join(thread_handle, NULL); | 190 pthread_join(thread_handle, NULL); |
| 293 } | 191 } |
| 294 | 192 |
| 295 #if !defined(OS_MACOSX) && !defined(OS_ANDROID) | 193 #if !defined(OS_LINUX) && !defined(OS_MACOSX) |
| 296 // Mac OS X uses lower-level mach APIs and Android uses Java APIs. | |
| 297 // static | 194 // static |
| 298 void PlatformThread::SetThreadPriority(PlatformThreadHandle, ThreadPriority) { | 195 void PlatformThread::SetName(const char* name) { |
| 299 // TODO(crogers): Implement, see http://crbug.com/116172 | 196 ThreadIdNameManager::GetInstance()->SetName(CurrentId(), name); |
| 197 tracked_objects::ThreadData::InitializeThreadContext(name); | |
| 198 | |
| 199 // (This should be relatively simple to implement for the BSDs; I | |
| 200 // just don't have one handy to test the code on.) | |
| 300 } | 201 } |
| 301 #endif | 202 #endif |
| 302 | 203 |
| 303 #if defined(OS_ANDROID) | 204 #if !defined(OS_MACOSX) && !defined(OS_LINUX) && !defined(OS_ANDROID) |
| 304 bool RegisterThreadUtils(JNIEnv* env) { | 205 void PlatformThread::SetThreadPriority(PlatformThreadHandle, |
| 305 return RegisterNativesImpl(env); | 206 PlatformThreadId id, |
| 207 ThreadPriority priority) { | |
| 306 } | 208 } |
| 307 #endif // defined(OS_ANDROID) | 209 #endif |
| 210 | |
| 211 #if !defined(OS_MACOSX) | |
|
jar (doing other things)
2013/05/03 23:54:07
This section is still messy (lines 193-230) with a
epennerAtGoogle
2013/05/04 01:09:45
Yes, I really did this for code clarity as opposed
| |
| 212 void InitThreading() { | |
| 213 } | |
| 214 #endif | |
| 215 | |
| 216 #if !defined(OS_ANDROID) | |
| 217 void InitOnThread() { | |
| 218 } | |
| 219 #endif | |
| 220 | |
| 221 #if !defined(OS_ANDROID) | |
| 222 void TerminateOnThread() { | |
| 223 } | |
| 224 #endif | |
| 225 | |
| 226 #if !defined(OS_MACOSX) && !defined(OS_IOS) | |
| 227 size_t GetDefaultThreadStackSize(const pthread_attr_t& attributes) { | |
| 228 return 0; | |
| 229 } | |
| 230 #endif | |
| 308 | 231 |
| 309 } // namespace base | 232 } // namespace base |
| OLD | NEW |