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