• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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