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 |