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