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