Home | History | Annotate | Download | only in threading
      1 // Copyright (c) 2011 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 #include <errno.h>
      8 #include <sched.h>
      9 
     10 #include "base/logging.h"
     11 #include "base/memory/scoped_ptr.h"
     12 #include "base/safe_strerror_posix.h"
     13 #include "base/threading/thread_restrictions.h"
     14 
     15 #if defined(OS_MACOSX)
     16 #include <mach/mach.h>
     17 #include <sys/resource.h>
     18 #include <algorithm>
     19 #endif
     20 
     21 #if defined(OS_LINUX)
     22 #include <dlfcn.h>
     23 #include <sys/prctl.h>
     24 #include <sys/syscall.h>
     25 #include <unistd.h>
     26 #endif
     27 
     28 #if defined(OS_NACL)
     29 #include <sys/nacl_syscalls.h>
     30 #endif
     31 
     32 namespace base {
     33 
     34 #if defined(OS_MACOSX)
     35 void InitThreading();
     36 #endif
     37 
     38 namespace {
     39 
     40 struct ThreadParams {
     41   PlatformThread::Delegate* delegate;
     42   bool joinable;
     43 };
     44 
     45 void* ThreadFunc(void* params) {
     46   ThreadParams* thread_params = static_cast<ThreadParams*>(params);
     47   PlatformThread::Delegate* delegate = thread_params->delegate;
     48   if (!thread_params->joinable)
     49     base::ThreadRestrictions::SetSingletonAllowed(false);
     50   delete thread_params;
     51   delegate->ThreadMain();
     52   return NULL;
     53 }
     54 
     55 bool CreateThread(size_t stack_size, bool joinable,
     56                   PlatformThread::Delegate* delegate,
     57                   PlatformThreadHandle* thread_handle) {
     58 #if defined(OS_MACOSX)
     59   base::InitThreading();
     60 #endif  // OS_MACOSX
     61 
     62   bool success = false;
     63   pthread_attr_t attributes;
     64   pthread_attr_init(&attributes);
     65 
     66   // Pthreads are joinable by default, so only specify the detached attribute if
     67   // the thread should be non-joinable.
     68   if (!joinable) {
     69     pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_DETACHED);
     70   }
     71 
     72 #if defined(OS_MACOSX)
     73   // The Mac OS X default for a pthread stack size is 512kB.
     74   // Libc-594.1.4/pthreads/pthread.c's pthread_attr_init uses
     75   // DEFAULT_STACK_SIZE for this purpose.
     76   //
     77   // 512kB isn't quite generous enough for some deeply recursive threads that
     78   // otherwise request the default stack size by specifying 0. Here, adopt
     79   // glibc's behavior as on Linux, which is to use the current stack size
     80   // limit (ulimit -s) as the default stack size. See
     81   // glibc-2.11.1/nptl/nptl-init.c's __pthread_initialize_minimal_internal. To
     82   // avoid setting the limit below the Mac OS X default or the minimum usable
     83   // stack size, these values are also considered. If any of these values
     84   // can't be determined, or if stack size is unlimited (ulimit -s unlimited),
     85   // stack_size is left at 0 to get the system default.
     86   //
     87   // Mac OS X normally only applies ulimit -s to the main thread stack. On
     88   // contemporary OS X and Linux systems alike, this value is generally 8MB
     89   // or in that neighborhood.
     90   if (stack_size == 0) {
     91     size_t default_stack_size;
     92     struct rlimit stack_rlimit;
     93     if (pthread_attr_getstacksize(&attributes, &default_stack_size) == 0 &&
     94         getrlimit(RLIMIT_STACK, &stack_rlimit) == 0 &&
     95         stack_rlimit.rlim_cur != RLIM_INFINITY) {
     96       stack_size = std::max(std::max(default_stack_size,
     97                                      static_cast<size_t>(PTHREAD_STACK_MIN)),
     98                             static_cast<size_t>(stack_rlimit.rlim_cur));
     99     }
    100   }
    101 #endif  // OS_MACOSX
    102 
    103   if (stack_size > 0)
    104     pthread_attr_setstacksize(&attributes, stack_size);
    105 
    106   ThreadParams* params = new ThreadParams;
    107   params->delegate = delegate;
    108   params->joinable = joinable;
    109   success = !pthread_create(thread_handle, &attributes, ThreadFunc, params);
    110 
    111   pthread_attr_destroy(&attributes);
    112   if (!success)
    113     delete params;
    114   return success;
    115 }
    116 
    117 }  // namespace
    118 
    119 // static
    120 PlatformThreadId PlatformThread::CurrentId() {
    121   // Pthreads doesn't have the concept of a thread ID, so we have to reach down
    122   // into the kernel.
    123 #if defined(OS_MACOSX)
    124   return mach_thread_self();
    125 #elif defined(OS_LINUX)
    126   return syscall(__NR_gettid);
    127 #elif defined(OS_FREEBSD)
    128   // TODO(BSD): find a better thread ID
    129   return reinterpret_cast<int64>(pthread_self());
    130 #elif defined(OS_NACL)
    131   return pthread_self();
    132 #endif
    133 }
    134 
    135 // static
    136 void PlatformThread::YieldCurrentThread() {
    137   sched_yield();
    138 }
    139 
    140 // static
    141 void PlatformThread::Sleep(int duration_ms) {
    142   struct timespec sleep_time, remaining;
    143 
    144   // Contains the portion of duration_ms >= 1 sec.
    145   sleep_time.tv_sec = duration_ms / 1000;
    146   duration_ms -= sleep_time.tv_sec * 1000;
    147 
    148   // Contains the portion of duration_ms < 1 sec.
    149   sleep_time.tv_nsec = duration_ms * 1000 * 1000;  // nanoseconds.
    150 
    151   while (nanosleep(&sleep_time, &remaining) == -1 && errno == EINTR)
    152     sleep_time = remaining;
    153 }
    154 
    155 // Linux SetName is currently disabled, as we need to distinguish between
    156 // helper threads (where it's ok to make this call) and the main thread
    157 // (where making this call renames our process, causing tools like killall
    158 // to stop working).
    159 #if 0 && defined(OS_LINUX)
    160 // static
    161 void PlatformThread::SetName(const char* name) {
    162   // http://0pointer.de/blog/projects/name-your-threads.html
    163 
    164   // glibc recently added support for pthread_setname_np, but it's not
    165   // commonly available yet.  So test for it at runtime.
    166   int (*dynamic_pthread_setname_np)(pthread_t, const char*);
    167   *reinterpret_cast<void**>(&dynamic_pthread_setname_np) =
    168       dlsym(RTLD_DEFAULT, "pthread_setname_np");
    169 
    170   if (dynamic_pthread_setname_np) {
    171     // This limit comes from glibc, which gets it from the kernel
    172     // (TASK_COMM_LEN).
    173     const int kMaxNameLength = 15;
    174     std::string shortened_name = std::string(name).substr(0, kMaxNameLength);
    175     int err = dynamic_pthread_setname_np(pthread_self(),
    176                                          shortened_name.c_str());
    177     if (err < 0)
    178       LOG(ERROR) << "pthread_setname_np: " << safe_strerror(err);
    179   } else {
    180     // Implementing this function without glibc is simple enough.  (We
    181     // don't do the name length clipping as above because it will be
    182     // truncated by the callee (see TASK_COMM_LEN above).)
    183     int err = prctl(PR_SET_NAME, name);
    184     if (err < 0)
    185       PLOG(ERROR) << "prctl(PR_SET_NAME)";
    186   }
    187 }
    188 #elif defined(OS_MACOSX)
    189 // Mac is implemented in platform_thread_mac.mm.
    190 #else
    191 // static
    192 void PlatformThread::SetName(const char* /*name*/) {
    193   // Leave it unimplemented.
    194 
    195   // (This should be relatively simple to implement for the BSDs; I
    196   // just don't have one handy to test the code on.)
    197 }
    198 #endif  // defined(OS_LINUX)
    199 
    200 // static
    201 bool PlatformThread::Create(size_t stack_size, Delegate* delegate,
    202                             PlatformThreadHandle* thread_handle) {
    203   return CreateThread(stack_size, true /* joinable thread */,
    204                       delegate, thread_handle);
    205 }
    206 
    207 // static
    208 bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) {
    209   PlatformThreadHandle unused;
    210 
    211   bool result = CreateThread(stack_size, false /* non-joinable thread */,
    212                              delegate, &unused);
    213   return result;
    214 }
    215 
    216 // static
    217 void PlatformThread::Join(PlatformThreadHandle thread_handle) {
    218   // Joining another thread may block the current thread for a long time, since
    219   // the thread referred to by |thread_handle| may still be running long-lived /
    220   // blocking tasks.
    221   base::ThreadRestrictions::AssertIOAllowed();
    222   pthread_join(thread_handle, NULL);
    223 }
    224 
    225 }  // namespace base
    226