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.
5 #include "base/threading/platform_thread.h"
7 #import <Foundation/Foundation.h>
10 #include <mach/mach.h>
11 #include <mach/mach_time.h>
12 #include <mach/thread_policy.h>
13 #include <sys/resource.h>
15 #include "base/lazy_instance.h"
16 #include "base/logging.h"
17 #include "base/threading/thread_id_name_manager.h"
18 #include "base/tracked_objects.h"
22 // If Cocoa is to be used on more than one thread, it must know that the
23 // application is multithreaded. Since it's possible to enter Cocoa code
24 // from threads created by pthread_thread_create, Cocoa won't necessarily
25 // be aware that the application is multithreaded. Spawning an NSThread is
26 // enough to get Cocoa to set up for multithreaded operation, so this is done
27 // if necessary before pthread_thread_create spawns any threads.
29 // http://developer.apple.com/documentation/Cocoa/Conceptual/Multithreading/CreatingThreads/chapter_4_section_4.html
30 void InitThreading() {
31 static BOOL multithreaded = [NSThread isMultiThreaded];
33 // +[NSObject class] is idempotent.
34 [NSThread detachNewThreadSelector:@selector(class)
35 toTarget:[NSObject class]
39 DCHECK([NSThread isMultiThreaded]);
44 void PlatformThread::SetName(const char* name) {
45 ThreadIdNameManager::GetInstance()->SetName(CurrentId(), name);
46 tracked_objects::ThreadData::InitializeThreadContext(name);
48 // pthread_setname_np is only available in 10.6 or later, so test
50 int (*dynamic_pthread_setname_np)(const char*);
51 *reinterpret_cast<void**>(&dynamic_pthread_setname_np) =
52 dlsym(RTLD_DEFAULT, "pthread_setname_np");
53 if (!dynamic_pthread_setname_np)
56 // Mac OS X does not expose the length limit of the name, so
58 const int kMaxNameLength = 63;
59 std::string shortened_name = std::string(name).substr(0, kMaxNameLength);
60 // pthread_setname() fails (harmlessly) in the sandbox, ignore when it does.
61 // See http://crbug.com/47058
62 dynamic_pthread_setname_np(shortened_name.c_str());
67 void SetPriorityNormal(mach_port_t mach_thread_id) {
68 // Make thread standard policy.
69 // Please note that this call could fail in rare cases depending
70 // on runtime conditions.
71 thread_standard_policy policy;
72 kern_return_t result = thread_policy_set(mach_thread_id,
73 THREAD_STANDARD_POLICY,
74 (thread_policy_t)&policy,
75 THREAD_STANDARD_POLICY_COUNT);
77 if (result != KERN_SUCCESS)
78 DVLOG(1) << "thread_policy_set() failure: " << result;
81 // Enables time-contraint policy and priority suitable for low-latency,
82 // glitch-resistant audio.
83 void SetPriorityRealtimeAudio(mach_port_t mach_thread_id) {
86 // Increase thread priority to real-time.
88 // Please note that the thread_policy_set() calls may fail in
89 // rare cases if the kernel decides the system is under heavy load
90 // and is unable to handle boosting the thread priority.
91 // In these cases we just return early and go on with life.
93 // Make thread fixed priority.
94 thread_extended_policy_data_t policy;
95 policy.timeshare = 0; // Set to 1 for a non-fixed thread.
96 result = thread_policy_set(mach_thread_id,
97 THREAD_EXTENDED_POLICY,
98 (thread_policy_t)&policy,
99 THREAD_EXTENDED_POLICY_COUNT);
100 if (result != KERN_SUCCESS) {
101 DVLOG(1) << "thread_policy_set() failure: " << result;
105 // Set to relatively high priority.
106 thread_precedence_policy_data_t precedence;
107 precedence.importance = 63;
108 result = thread_policy_set(mach_thread_id,
109 THREAD_PRECEDENCE_POLICY,
110 (thread_policy_t)&precedence,
111 THREAD_PRECEDENCE_POLICY_COUNT);
112 if (result != KERN_SUCCESS) {
113 DVLOG(1) << "thread_policy_set() failure: " << result;
117 // Most important, set real-time constraints.
119 // Define the guaranteed and max fraction of time for the audio thread.
120 // These "duty cycle" values can range from 0 to 1. A value of 0.5
121 // means the scheduler would give half the time to the thread.
122 // These values have empirically been found to yield good behavior.
123 // Good means that audio performance is high and other threads won't starve.
124 const double kGuaranteedAudioDutyCycle = 0.75;
125 const double kMaxAudioDutyCycle = 0.85;
127 // Define constants determining how much time the audio thread can
128 // use in a given time quantum. All times are in milliseconds.
130 // About 128 frames @44.1KHz
131 const double kTimeQuantum = 2.9;
133 // Time guaranteed each quantum.
134 const double kAudioTimeNeeded = kGuaranteedAudioDutyCycle * kTimeQuantum;
136 // Maximum time each quantum.
137 const double kMaxTimeAllowed = kMaxAudioDutyCycle * kTimeQuantum;
139 // Get the conversion factor from milliseconds to absolute time
140 // which is what the time-constraints call needs.
141 mach_timebase_info_data_t tb_info;
142 mach_timebase_info(&tb_info);
143 double ms_to_abs_time =
144 ((double)tb_info.denom / (double)tb_info.numer) * 1000000;
146 thread_time_constraint_policy_data_t time_constraints;
147 time_constraints.period = kTimeQuantum * ms_to_abs_time;
148 time_constraints.computation = kAudioTimeNeeded * ms_to_abs_time;
149 time_constraints.constraint = kMaxTimeAllowed * ms_to_abs_time;
150 time_constraints.preemptible = 0;
152 result = thread_policy_set(mach_thread_id,
153 THREAD_TIME_CONSTRAINT_POLICY,
154 (thread_policy_t)&time_constraints,
155 THREAD_TIME_CONSTRAINT_POLICY_COUNT);
156 if (result != KERN_SUCCESS)
157 DVLOG(1) << "thread_policy_set() failure: " << result;
162 } // anonymous namespace
165 void PlatformThread::SetThreadPriority(PlatformThreadHandle handle,
166 ThreadPriority priority) {
167 // Convert from pthread_t to mach thread identifier.
168 mach_port_t mach_thread_id = pthread_mach_thread_np(handle.handle_);
171 case kThreadPriority_Normal:
172 SetPriorityNormal(mach_thread_id);
174 case kThreadPriority_RealtimeAudio:
175 SetPriorityRealtimeAudio(mach_thread_id);
178 NOTREACHED() << "Unknown priority.";
183 size_t GetDefaultThreadStackSize(const pthread_attr_t& attributes) {
187 // The Mac OS X default for a pthread stack size is 512kB.
188 // Libc-594.1.4/pthreads/pthread.c's pthread_attr_init uses
189 // DEFAULT_STACK_SIZE for this purpose.
191 // 512kB isn't quite generous enough for some deeply recursive threads that
192 // otherwise request the default stack size by specifying 0. Here, adopt
193 // glibc's behavior as on Linux, which is to use the current stack size
194 // limit (ulimit -s) as the default stack size. See
195 // glibc-2.11.1/nptl/nptl-init.c's __pthread_initialize_minimal_internal. To
196 // avoid setting the limit below the Mac OS X default or the minimum usable
197 // stack size, these values are also considered. If any of these values
198 // can't be determined, or if stack size is unlimited (ulimit -s unlimited),
199 // stack_size is left at 0 to get the system default.
201 // Mac OS X normally only applies ulimit -s to the main thread stack. On
202 // contemporary OS X and Linux systems alike, this value is generally 8MB
203 // or in that neighborhood.
204 size_t default_stack_size = 0;
205 struct rlimit stack_rlimit;
206 if (pthread_attr_getstacksize(&attributes, &default_stack_size) == 0 &&
207 getrlimit(RLIMIT_STACK, &stack_rlimit) == 0 &&
208 stack_rlimit.rlim_cur != RLIM_INFINITY) {
210 std::max(std::max(default_stack_size,
211 static_cast<size_t>(PTHREAD_STACK_MIN)),
212 static_cast<size_t>(stack_rlimit.rlim_cur));
214 return default_stack_size;
218 void InitOnThread() {
221 void TerminateOnThread() {