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 #include <errno.h>
      8 #include <pthread.h>
      9 #include <sched.h>
     10 #include <stddef.h>
     11 #include <stdint.h>
     12 #include <sys/resource.h>
     13 #include <sys/time.h>
     14 
     15 #include "base/lazy_instance.h"
     16 #include "base/logging.h"
     17 #include "base/memory/scoped_ptr.h"
     18 #include "base/threading/platform_thread_internal_posix.h"
     19 #include "base/threading/thread_id_name_manager.h"
     20 #include "base/threading/thread_restrictions.h"
     21 #include "build/build_config.h"
     22 
     23 #if defined(OS_LINUX)
     24 #include <sys/syscall.h>
     25 #elif defined(OS_ANDROID)
     26 #include <sys/types.h>
     27 #endif
     28 
     29 namespace base {
     30 
     31 void InitThreading();
     32 void InitOnThread();
     33 void TerminateOnThread();
     34 size_t GetDefaultThreadStackSize(const pthread_attr_t& attributes);
     35 
     36 namespace {
     37 
     38 struct ThreadParams {
     39   ThreadParams()
     40       : delegate(NULL), joinable(false), priority(ThreadPriority::NORMAL) {}
     41 
     42   PlatformThread::Delegate* delegate;
     43   bool joinable;
     44   ThreadPriority priority;
     45 };
     46 
     47 void* ThreadFunc(void* params) {
     48   base::InitOnThread();
     49 
     50   PlatformThread::Delegate* delegate = nullptr;
     51 
     52   {
     53     scoped_ptr<ThreadParams> thread_params(static_cast<ThreadParams*>(params));
     54 
     55     delegate = thread_params->delegate;
     56     if (!thread_params->joinable)
     57       base::ThreadRestrictions::SetSingletonAllowed(false);
     58 
     59     if (thread_params->priority != ThreadPriority::NORMAL)
     60       PlatformThread::SetCurrentThreadPriority(thread_params->priority);
     61   }
     62 
     63   ThreadIdNameManager::GetInstance()->RegisterThread(
     64       PlatformThread::CurrentHandle().platform_handle(),
     65       PlatformThread::CurrentId());
     66 
     67   delegate->ThreadMain();
     68 
     69   ThreadIdNameManager::GetInstance()->RemoveName(
     70       PlatformThread::CurrentHandle().platform_handle(),
     71       PlatformThread::CurrentId());
     72 
     73   base::TerminateOnThread();
     74   return NULL;
     75 }
     76 
     77 bool CreateThread(size_t stack_size,
     78                   bool joinable,
     79                   PlatformThread::Delegate* delegate,
     80                   PlatformThreadHandle* thread_handle,
     81                   ThreadPriority priority) {
     82   DCHECK(thread_handle);
     83   base::InitThreading();
     84 
     85   pthread_attr_t attributes;
     86   pthread_attr_init(&attributes);
     87 
     88   // Pthreads are joinable by default, so only specify the detached
     89   // attribute if the thread should be non-joinable.
     90   if (!joinable)
     91     pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_DETACHED);
     92 
     93   // Get a better default if available.
     94   if (stack_size == 0)
     95     stack_size = base::GetDefaultThreadStackSize(attributes);
     96 
     97   if (stack_size > 0)
     98     pthread_attr_setstacksize(&attributes, stack_size);
     99 
    100   scoped_ptr<ThreadParams> params(new ThreadParams);
    101   params->delegate = delegate;
    102   params->joinable = joinable;
    103   params->priority = priority;
    104 
    105   pthread_t handle;
    106   int err = pthread_create(&handle, &attributes, ThreadFunc, params.get());
    107   bool success = !err;
    108   if (success) {
    109     // ThreadParams should be deleted on the created thread after used.
    110     ignore_result(params.release());
    111   } else {
    112     // Value of |handle| is undefined if pthread_create fails.
    113     handle = 0;
    114     errno = err;
    115     PLOG(ERROR) << "pthread_create";
    116   }
    117   *thread_handle = PlatformThreadHandle(handle);
    118 
    119   pthread_attr_destroy(&attributes);
    120 
    121   return success;
    122 }
    123 
    124 }  // namespace
    125 
    126 // static
    127 PlatformThreadId PlatformThread::CurrentId() {
    128   // Pthreads doesn't have the concept of a thread ID, so we have to reach down
    129   // into the kernel.
    130 #if defined(OS_MACOSX)
    131   return pthread_mach_thread_np(pthread_self());
    132 #elif defined(OS_LINUX)
    133   return syscall(__NR_gettid);
    134 #elif defined(OS_ANDROID)
    135   return gettid();
    136 #elif defined(OS_SOLARIS) || defined(OS_QNX)
    137   return pthread_self();
    138 #elif defined(OS_NACL) && defined(__GLIBC__)
    139   return pthread_self();
    140 #elif defined(OS_NACL) && !defined(__GLIBC__)
    141   // Pointers are 32-bits in NaCl.
    142   return reinterpret_cast<int32_t>(pthread_self());
    143 #elif defined(OS_POSIX)
    144   return reinterpret_cast<int64_t>(pthread_self());
    145 #endif
    146 }
    147 
    148 // static
    149 PlatformThreadRef PlatformThread::CurrentRef() {
    150   return PlatformThreadRef(pthread_self());
    151 }
    152 
    153 // static
    154 PlatformThreadHandle PlatformThread::CurrentHandle() {
    155   return PlatformThreadHandle(pthread_self());
    156 }
    157 
    158 // static
    159 void PlatformThread::YieldCurrentThread() {
    160   sched_yield();
    161 }
    162 
    163 // static
    164 void PlatformThread::Sleep(TimeDelta duration) {
    165   struct timespec sleep_time, remaining;
    166 
    167   // Break the duration into seconds and nanoseconds.
    168   // NOTE: TimeDelta's microseconds are int64s while timespec's
    169   // nanoseconds are longs, so this unpacking must prevent overflow.
    170   sleep_time.tv_sec = duration.InSeconds();
    171   duration -= TimeDelta::FromSeconds(sleep_time.tv_sec);
    172   sleep_time.tv_nsec = duration.InMicroseconds() * 1000;  // nanoseconds
    173 
    174   while (nanosleep(&sleep_time, &remaining) == -1 && errno == EINTR)
    175     sleep_time = remaining;
    176 }
    177 
    178 // static
    179 const char* PlatformThread::GetName() {
    180   return ThreadIdNameManager::GetInstance()->GetName(CurrentId());
    181 }
    182 
    183 // static
    184 bool PlatformThread::CreateWithPriority(size_t stack_size, Delegate* delegate,
    185                                         PlatformThreadHandle* thread_handle,
    186                                         ThreadPriority priority) {
    187   return CreateThread(stack_size, true,  // joinable thread
    188                       delegate, thread_handle, priority);
    189 }
    190 
    191 // static
    192 bool PlatformThread::CreateNonJoinable(size_t stack_size, Delegate* delegate) {
    193   PlatformThreadHandle unused;
    194 
    195   bool result = CreateThread(stack_size, false /* non-joinable thread */,
    196                              delegate, &unused, ThreadPriority::NORMAL);
    197   return result;
    198 }
    199 
    200 // static
    201 void PlatformThread::Join(PlatformThreadHandle thread_handle) {
    202   // Joining another thread may block the current thread for a long time, since
    203   // the thread referred to by |thread_handle| may still be running long-lived /
    204   // blocking tasks.
    205   base::ThreadRestrictions::AssertIOAllowed();
    206   CHECK_EQ(0, pthread_join(thread_handle.platform_handle(), NULL));
    207 }
    208 
    209 // Mac has its own Set/GetCurrentThreadPriority() implementations.
    210 #if !defined(OS_MACOSX)
    211 
    212 // static
    213 void PlatformThread::SetCurrentThreadPriority(ThreadPriority priority) {
    214 #if defined(OS_NACL)
    215   NOTIMPLEMENTED();
    216 #else
    217   if (internal::SetCurrentThreadPriorityForPlatform(priority))
    218     return;
    219 
    220   // setpriority(2) should change the whole thread group's (i.e. process)
    221   // priority. However, as stated in the bugs section of
    222   // http://man7.org/linux/man-pages/man2/getpriority.2.html: "under the current
    223   // Linux/NPTL implementation of POSIX threads, the nice value is a per-thread
    224   // attribute". Also, 0 is prefered to the current thread id since it is
    225   // equivalent but makes sandboxing easier (https://crbug.com/399473).
    226   const int nice_setting = internal::ThreadPriorityToNiceValue(priority);
    227   if (setpriority(PRIO_PROCESS, 0, nice_setting)) {
    228     DVPLOG(1) << "Failed to set nice value of thread ("
    229               << PlatformThread::CurrentId() << ") to " << nice_setting;
    230   }
    231 #endif  // defined(OS_NACL)
    232 }
    233 
    234 // static
    235 ThreadPriority PlatformThread::GetCurrentThreadPriority() {
    236 #if defined(OS_NACL)
    237   NOTIMPLEMENTED();
    238   return ThreadPriority::NORMAL;
    239 #else
    240   // Mirrors SetCurrentThreadPriority()'s implementation.
    241   ThreadPriority platform_specific_priority;
    242   if (internal::GetCurrentThreadPriorityForPlatform(
    243           &platform_specific_priority)) {
    244     return platform_specific_priority;
    245   }
    246 
    247   // Need to clear errno before calling getpriority():
    248   // http://man7.org/linux/man-pages/man2/getpriority.2.html
    249   errno = 0;
    250   int nice_value = getpriority(PRIO_PROCESS, 0);
    251   if (errno != 0) {
    252     DVPLOG(1) << "Failed to get nice value of thread ("
    253               << PlatformThread::CurrentId() << ")";
    254     return ThreadPriority::NORMAL;
    255   }
    256 
    257   return internal::NiceValueToThreadPriority(nice_value);
    258 #endif  // !defined(OS_NACL)
    259 }
    260 
    261 #endif  // !defined(OS_MACOSX)
    262 
    263 }  // namespace base
    264