Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(301)

Side by Side Diff: base/threading/platform_thread_posix.cc

Issue 12741012: base: Support setting thread priorities generically. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase. Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/threading/platform_thread_mac.mm ('k') | base/threading/platform_thread_win.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
OLDNEW
« no previous file with comments | « base/threading/platform_thread_mac.mm ('k') | base/threading/platform_thread_win.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698