Home | History | Annotate | Download | only in threading
      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 
     21 namespace 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
     31 void 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
     45 void 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 
     58 namespace {
     59 
     60 void 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.
     77 void 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
    158 void 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 
    176 size_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 
    211 void InitOnThread() {
    212 }
    213 
    214 void TerminateOnThread() {
    215 }
    216 
    217 }  // namespace base
    218