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. 4 5#include "base/threading/platform_thread.h" 6 7#import <Foundation/Foundation.h> 8#include <algorithm> 9#include <dlfcn.h> 10#include <mach/mach.h> 11#include <mach/mach_time.h> 12#include <mach/thread_policy.h> 13#include <sys/resource.h> 14 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" 19 20namespace base { 21 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. 28// 29// http://developer.apple.com/documentation/Cocoa/Conceptual/Multithreading/CreatingThreads/chapter_4_section_4.html 30void InitThreading() { 31 static BOOL multithreaded = [NSThread isMultiThreaded]; 32 if (!multithreaded) { 33 // +[NSObject class] is idempotent. 34 [NSThread detachNewThreadSelector:@selector(class) 35 toTarget:[NSObject class] 36 withObject:nil]; 37 multithreaded = YES; 38 39 DCHECK([NSThread isMultiThreaded]); 40 } 41} 42 43// static 44void PlatformThread::SetName(const char* name) { 45 ThreadIdNameManager::GetInstance()->SetName(CurrentId(), name); 46 tracked_objects::ThreadData::InitializeThreadContext(name); 47 48 // pthread_setname_np is only available in 10.6 or later, so test 49 // for it at runtime. 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) 54 return; 55 56 // Mac OS X does not expose the length limit of the name, so 57 // hardcode it. 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()); 63} 64 65namespace { 66 67void 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); 76 77 if (result != KERN_SUCCESS) 78 DVLOG(1) << "thread_policy_set() failure: " << result; 79} 80 81// Enables time-contraint policy and priority suitable for low-latency, 82// glitch-resistant audio. 83void SetPriorityRealtimeAudio(mach_port_t mach_thread_id) { 84 kern_return_t result; 85 86 // Increase thread priority to real-time. 87 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. 92 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; 102 return; 103 } 104 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; 114 return; 115 } 116 117 // Most important, set real-time constraints. 118 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; 126 127 // Define constants determining how much time the audio thread can 128 // use in a given time quantum. All times are in milliseconds. 129 130 // About 128 frames @44.1KHz 131 const double kTimeQuantum = 2.9; 132 133 // Time guaranteed each quantum. 134 const double kAudioTimeNeeded = kGuaranteedAudioDutyCycle * kTimeQuantum; 135 136 // Maximum time each quantum. 137 const double kMaxTimeAllowed = kMaxAudioDutyCycle * kTimeQuantum; 138 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; 145 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; 151 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; 158 159 return; 160} 161 162} // anonymous namespace 163 164// static 165void 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_); 169 170 switch (priority) { 171 case kThreadPriority_Normal: 172 SetPriorityNormal(mach_thread_id); 173 break; 174 case kThreadPriority_RealtimeAudio: 175 SetPriorityRealtimeAudio(mach_thread_id); 176 break; 177 default: 178 NOTREACHED() << "Unknown priority."; 179 break; 180 } 181} 182 183size_t GetDefaultThreadStackSize(const pthread_attr_t& attributes) { 184#if defined(OS_IOS) 185 return 0; 186#else 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. 190 // 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. 200 // 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) { 209 default_stack_size = 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)); 213 } 214 return default_stack_size; 215#endif 216} 217 218void InitOnThread() { 219} 220 221void TerminateOnThread() { 222} 223 224} // namespace base 225