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