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 <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 
     23 namespace 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
     33 void 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
     47 void 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 
     60 namespace {
     61 
     62 void 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.
     79 void 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
    160 void 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
    179 ThreadPriority PlatformThread::GetCurrentThreadPriority() {
    180   NOTIMPLEMENTED();
    181   return ThreadPriority::NORMAL;
    182 }
    183 
    184 size_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 
    219 void InitOnThread() {
    220 }
    221 
    222 void TerminateOnThread() {
    223 }
    224 
    225 }  // namespace base
    226