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