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