tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

platform_thread_posix.cc (14126B)


      1 // Copyright 2012 The Chromium Authors
      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/notreached.h"
      6 #include "base/threading/platform_thread.h"
      7 
      8 #include <errno.h>
      9 #include <pthread.h>
     10 #include <sched.h>
     11 #include <stddef.h>
     12 #include <stdint.h>
     13 #include <sys/time.h>
     14 #include <sys/types.h>
     15 #include <unistd.h>
     16 
     17 #include <memory>
     18 #include <tuple>
     19 
     20 #include "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_buildflags.h"
     21 #include "base/compiler_specific.h"
     22 #include "base/lazy_instance.h"
     23 #include "base/logging.h"
     24 #include "base/memory/raw_ptr.h"
     25 #include "base/threading/platform_thread_internal_posix.h"
     26 #include "base/threading/scoped_blocking_call.h"
     27 #include "base/threading/thread_id_name_manager.h"
     28 #include "base/threading/thread_restrictions.h"
     29 #include "build/build_config.h"
     30 
     31 #if !BUILDFLAG(IS_APPLE) && !BUILDFLAG(IS_FUCHSIA) && !BUILDFLAG(IS_NACL)
     32 #include "base/posix/can_lower_nice_to.h"
     33 #endif
     34 
     35 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
     36 #include <sys/syscall.h>
     37 #include <atomic>
     38 #endif
     39 
     40 #if BUILDFLAG(IS_FUCHSIA)
     41 #include <zircon/process.h>
     42 #else
     43 #include <sys/resource.h>
     44 #endif
     45 
     46 #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && BUILDFLAG(USE_STARSCAN)
     47 #include "base/allocator/partition_allocator/src/partition_alloc/starscan/pcscan.h"
     48 #include "base/allocator/partition_allocator/src/partition_alloc/starscan/stack/stack.h"
     49 #endif
     50 
     51 namespace base {
     52 
     53 void InitThreading();
     54 void TerminateOnThread();
     55 size_t GetDefaultThreadStackSize(const pthread_attr_t& attributes);
     56 
     57 namespace {
     58 
     59 #if !defined(MOZ_SANDBOX)
     60 struct ThreadParams {
     61  ThreadParams() = default;
     62 
     63  raw_ptr<PlatformThread::Delegate> delegate = nullptr;
     64  bool joinable = false;
     65  ThreadType thread_type = ThreadType::kDefault;
     66  MessagePumpType message_pump_type = MessagePumpType::DEFAULT;
     67 };
     68 
     69 void* ThreadFunc(void* params) {
     70  PlatformThread::Delegate* delegate = nullptr;
     71 
     72  {
     73    std::unique_ptr<ThreadParams> thread_params(
     74        static_cast<ThreadParams*>(params));
     75 
     76    delegate = thread_params->delegate;
     77    if (!thread_params->joinable)
     78      base::DisallowSingleton();
     79 
     80 #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && BUILDFLAG(USE_STARSCAN)
     81    partition_alloc::internal::PCScan::NotifyThreadCreated(
     82        partition_alloc::internal::GetStackPointer());
     83 #endif
     84 
     85 #if !BUILDFLAG(IS_NACL)
     86 #if BUILDFLAG(IS_APPLE)
     87    PlatformThread::SetCurrentThreadRealtimePeriodValue(
     88        delegate->GetRealtimePeriod());
     89 #endif
     90 
     91    // Threads on linux/android may inherit their priority from the thread
     92    // where they were created. This explicitly sets the priority of all new
     93    // threads.
     94    PlatformThread::SetCurrentThreadType(thread_params->thread_type);
     95 #endif  //  !BUILDFLAG(IS_NACL)
     96  }
     97 
     98  ThreadIdNameManager::GetInstance()->RegisterThread(
     99      PlatformThread::CurrentHandle().platform_handle(),
    100      PlatformThread::CurrentId());
    101 
    102  delegate->ThreadMain();
    103 
    104  ThreadIdNameManager::GetInstance()->RemoveName(
    105      PlatformThread::CurrentHandle().platform_handle(),
    106      PlatformThread::CurrentId());
    107 
    108 #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC) && BUILDFLAG(USE_STARSCAN)
    109  partition_alloc::internal::PCScan::NotifyThreadDestroyed();
    110 #endif
    111 
    112  base::TerminateOnThread();
    113  return nullptr;
    114 }
    115 
    116 bool CreateThread(size_t stack_size,
    117                  bool joinable,
    118                  PlatformThread::Delegate* delegate,
    119                  PlatformThreadHandle* thread_handle,
    120                  ThreadType thread_type,
    121                  MessagePumpType message_pump_type) {
    122  DCHECK(thread_handle);
    123  base::InitThreading();
    124 
    125  pthread_attr_t attributes;
    126  pthread_attr_init(&attributes);
    127 
    128  // Pthreads are joinable by default, so only specify the detached
    129  // attribute if the thread should be non-joinable.
    130  if (!joinable)
    131    pthread_attr_setdetachstate(&attributes, PTHREAD_CREATE_DETACHED);
    132 
    133  // Get a better default if available.
    134  if (stack_size == 0)
    135    stack_size = base::GetDefaultThreadStackSize(attributes);
    136 
    137  if (stack_size > 0)
    138    pthread_attr_setstacksize(&attributes, stack_size);
    139 
    140  std::unique_ptr<ThreadParams> params(new ThreadParams);
    141  params->delegate = delegate;
    142  params->joinable = joinable;
    143  params->thread_type = thread_type;
    144  params->message_pump_type = message_pump_type;
    145 
    146  pthread_t handle;
    147  int err = pthread_create(&handle, &attributes, ThreadFunc, params.get());
    148  bool success = !err;
    149  if (success) {
    150    // ThreadParams should be deleted on the created thread after used.
    151    std::ignore = params.release();
    152  } else {
    153    // Value of |handle| is undefined if pthread_create fails.
    154    handle = 0;
    155    errno = err;
    156    PLOG(ERROR) << "pthread_create";
    157  }
    158  *thread_handle = PlatformThreadHandle(handle);
    159 
    160  pthread_attr_destroy(&attributes);
    161 
    162  return success;
    163 }
    164 #endif
    165 
    166 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
    167 
    168 // Store the thread ids in local storage since calling the SWI can be
    169 // expensive and PlatformThread::CurrentId is used liberally.
    170 thread_local pid_t g_thread_id = -1;
    171 
    172 // A boolean value that indicates that the value stored in |g_thread_id| on the
    173 // main thread is invalid, because it hasn't been updated since the process
    174 // forked.
    175 //
    176 // This used to work by setting |g_thread_id| to -1 in a pthread_atfork handler.
    177 // However, when a multithreaded process forks, it is only allowed to call
    178 // async-signal-safe functions until it calls an exec() syscall. However,
    179 // accessing TLS may allocate (see crbug.com/1275748), which is not
    180 // async-signal-safe and therefore causes deadlocks, corruption, and crashes.
    181 //
    182 // It's Atomic to placate TSAN.
    183 std::atomic<bool> g_main_thread_tid_cache_valid = false;
    184 
    185 // Tracks whether the current thread is the main thread, and therefore whether
    186 // |g_main_thread_tid_cache_valid| is relevant for the current thread. This is
    187 // also updated by PlatformThread::CurrentId().
    188 thread_local bool g_is_main_thread = true;
    189 
    190 class InitAtFork {
    191 public:
    192  InitAtFork() {
    193    pthread_atfork(nullptr, nullptr, internal::InvalidateTidCache);
    194  }
    195 };
    196 
    197 #endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
    198 
    199 }  // namespace
    200 
    201 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
    202 
    203 namespace internal {
    204 
    205 void InvalidateTidCache() {
    206  g_main_thread_tid_cache_valid.store(false, std::memory_order_relaxed);
    207 }
    208 
    209 }  // namespace internal
    210 
    211 #endif  // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
    212 
    213 // static
    214 PlatformThreadId PlatformThreadBase::CurrentId() {
    215  // Pthreads doesn't have the concept of a thread ID, so we have to reach down
    216  // into the kernel.
    217 #if BUILDFLAG(IS_APPLE)
    218  return pthread_mach_thread_np(pthread_self());
    219 #elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
    220  // Workaround false-positive MSAN use-of-uninitialized-value on
    221  // thread_local storage for loaded libraries:
    222  // https://github.com/google/sanitizers/issues/1265
    223  MSAN_UNPOISON(&g_thread_id, sizeof(pid_t));
    224  MSAN_UNPOISON(&g_is_main_thread, sizeof(bool));
    225  static InitAtFork init_at_fork;
    226  if (g_thread_id == -1 ||
    227      (g_is_main_thread &&
    228       !g_main_thread_tid_cache_valid.load(std::memory_order_relaxed))) {
    229    // Update the cached tid.
    230    g_thread_id = static_cast<pid_t>(syscall(__NR_gettid));
    231    // If this is the main thread, we can mark the tid_cache as valid.
    232    // Otherwise, stop the current thread from always entering this slow path.
    233    if (g_thread_id == getpid()) {
    234      g_main_thread_tid_cache_valid.store(true, std::memory_order_relaxed);
    235    } else {
    236      g_is_main_thread = false;
    237    }
    238  } else {
    239 #if DCHECK_IS_ON()
    240    if (g_thread_id != syscall(__NR_gettid)) {
    241      RAW_LOG(
    242          FATAL,
    243          "Thread id stored in TLS is different from thread id returned by "
    244          "the system. It is likely that the process was forked without going "
    245          "through fork().");
    246    }
    247 #endif
    248  }
    249  return g_thread_id;
    250 #elif BUILDFLAG(IS_ANDROID)
    251  // Note: do not cache the return value inside a thread_local variable on
    252  // Android (as above). The reasons are:
    253  // - thread_local is slow on Android (goes through emutls)
    254  // - gettid() is fast, since its return value is cached in pthread (in the
    255  //   thread control block of pthread). See gettid.c in bionic.
    256  return gettid();
    257 #elif BUILDFLAG(IS_FUCHSIA)
    258  return zx_thread_self();
    259 #elif BUILDFLAG(IS_SOLARIS) || BUILDFLAG(IS_QNX)
    260  return pthread_self();
    261 #elif BUILDFLAG(IS_NACL) && defined(__GLIBC__)
    262  return pthread_self();
    263 #elif BUILDFLAG(IS_NACL) && !defined(__GLIBC__)
    264  // Pointers are 32-bits in NaCl.
    265  return reinterpret_cast<int32_t>(pthread_self());
    266 #elif BUILDFLAG(IS_POSIX) && BUILDFLAG(IS_AIX)
    267  return pthread_self();
    268 #elif BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_AIX)
    269  return reinterpret_cast<int64_t>(pthread_self());
    270 #endif
    271 }
    272 
    273 // static
    274 PlatformThreadRef PlatformThreadBase::CurrentRef() {
    275  return PlatformThreadRef(pthread_self());
    276 }
    277 
    278 // static
    279 PlatformThreadHandle PlatformThreadBase::CurrentHandle() {
    280  return PlatformThreadHandle(pthread_self());
    281 }
    282 
    283 #if !BUILDFLAG(IS_APPLE)
    284 // static
    285 void PlatformThreadBase::YieldCurrentThread() {
    286  sched_yield();
    287 }
    288 #endif  // !BUILDFLAG(IS_APPLE)
    289 
    290 // static
    291 void PlatformThreadBase::Sleep(TimeDelta duration) {
    292  struct timespec sleep_time, remaining;
    293 
    294  // Break the duration into seconds and nanoseconds.
    295  // NOTE: TimeDelta's microseconds are int64s while timespec's
    296  // nanoseconds are longs, so this unpacking must prevent overflow.
    297  sleep_time.tv_sec = static_cast<time_t>(duration.InSeconds());
    298  duration -= Seconds(sleep_time.tv_sec);
    299  sleep_time.tv_nsec = static_cast<long>(duration.InMicroseconds() * 1000);
    300 
    301  while (nanosleep(&sleep_time, &remaining) == -1 && errno == EINTR)
    302    sleep_time = remaining;
    303 }
    304 
    305 // static
    306 const char* PlatformThreadBase::GetName() {
    307  return ThreadIdNameManager::GetInstance()->GetName(CurrentId());
    308 }
    309 
    310 #if !defined(MOZ_SANDBOX)
    311 // static
    312 bool PlatformThreadBase::CreateWithType(size_t stack_size,
    313                                    Delegate* delegate,
    314                                    PlatformThreadHandle* thread_handle,
    315                                    ThreadType thread_type,
    316                                    MessagePumpType pump_type_hint) {
    317  return CreateThread(stack_size, true /* joinable thread */, delegate,
    318                      thread_handle, thread_type, pump_type_hint);
    319 }
    320 
    321 // static
    322 bool PlatformThreadBase::CreateNonJoinable(size_t stack_size, Delegate* delegate) {
    323  return CreateNonJoinableWithType(stack_size, delegate, ThreadType::kDefault);
    324 }
    325 
    326 // static
    327 bool PlatformThreadBase::CreateNonJoinableWithType(size_t stack_size,
    328                                               Delegate* delegate,
    329                                               ThreadType thread_type,
    330                                               MessagePumpType pump_type_hint) {
    331  PlatformThreadHandle unused;
    332 
    333  bool result = CreateThread(stack_size, false /* non-joinable thread */,
    334                             delegate, &unused, thread_type, pump_type_hint);
    335  return result;
    336 }
    337 #endif
    338 
    339 // static
    340 void PlatformThreadBase::Join(PlatformThreadHandle thread_handle) {
    341  // Joining another thread may block the current thread for a long time, since
    342  // the thread referred to by |thread_handle| may still be running long-lived /
    343  // blocking tasks.
    344  base::internal::ScopedBlockingCallWithBaseSyncPrimitives scoped_blocking_call(
    345      FROM_HERE, base::BlockingType::MAY_BLOCK);
    346  CHECK_EQ(0, pthread_join(thread_handle.platform_handle(), nullptr));
    347 }
    348 
    349 // static
    350 void PlatformThreadBase::Detach(PlatformThreadHandle thread_handle) {
    351  CHECK_EQ(0, pthread_detach(thread_handle.platform_handle()));
    352 }
    353 
    354 // Mac and Fuchsia have their own SetCurrentThreadType() and
    355 // GetCurrentThreadPriorityForTest() implementations.
    356 #if !BUILDFLAG(IS_APPLE) && !BUILDFLAG(IS_FUCHSIA)
    357 
    358 #if !defined(MOZ_SANDBOX)
    359 // static
    360 bool PlatformThreadBase::CanChangeThreadType(ThreadType from, ThreadType to) {
    361 #if BUILDFLAG(IS_NACL)
    362  return false;
    363 #else
    364  if (from >= to) {
    365    // Decreasing thread priority on POSIX is always allowed.
    366    return true;
    367  }
    368  if (to == ThreadType::kRealtimeAudio) {
    369    return internal::CanSetThreadTypeToRealtimeAudio();
    370  }
    371 
    372  return internal::CanLowerNiceTo(internal::ThreadTypeToNiceValue(to));
    373 #endif  // BUILDFLAG(IS_NACL)
    374 }
    375 #endif
    376 
    377 namespace internal {
    378 
    379 void SetCurrentThreadTypeImpl(ThreadType thread_type,
    380                              MessagePumpType pump_type_hint) {
    381 #if BUILDFLAG(IS_NACL)
    382  NOTIMPLEMENTED();
    383 #else
    384  if (internal::SetCurrentThreadTypeForPlatform(thread_type, pump_type_hint))
    385    return;
    386 
    387  // setpriority(2) should change the whole thread group's (i.e. process)
    388  // priority. However, as stated in the bugs section of
    389  // http://man7.org/linux/man-pages/man2/getpriority.2.html: "under the current
    390  // Linux/NPTL implementation of POSIX threads, the nice value is a per-thread
    391  // attribute". Also, 0 is prefered to the current thread id since it is
    392  // equivalent but makes sandboxing easier (https://crbug.com/399473).
    393  const int nice_setting = internal::ThreadTypeToNiceValue(thread_type);
    394  if (setpriority(PRIO_PROCESS, 0, nice_setting)) {
    395    DVPLOG(1) << "Failed to set nice value of thread ("
    396              << PlatformThread::CurrentId() << ") to " << nice_setting;
    397  }
    398 #endif  // BUILDFLAG(IS_NACL)
    399 }
    400 
    401 }  // namespace internal
    402 
    403 // static
    404 ThreadPriorityForTest PlatformThreadBase::GetCurrentThreadPriorityForTest() {
    405 #if BUILDFLAG(IS_NACL)
    406  NOTIMPLEMENTED();
    407  return ThreadPriorityForTest::kNormal;
    408 #else
    409  // Mirrors SetCurrentThreadPriority()'s implementation.
    410  auto platform_specific_priority =
    411      internal::GetCurrentThreadPriorityForPlatformForTest();  // IN-TEST
    412  if (platform_specific_priority)
    413    return platform_specific_priority.value();
    414 
    415  int nice_value = internal::GetCurrentThreadNiceValue();
    416 
    417  return internal::NiceValueToThreadPriorityForTest(nice_value);  // IN-TEST
    418 #endif  // !BUILDFLAG(IS_NACL)
    419 }
    420 
    421 #endif  // !BUILDFLAG(IS_APPLE) && !BUILDFLAG(IS_FUCHSIA)
    422 
    423 // static
    424 size_t PlatformThreadBase::GetDefaultThreadStackSize() {
    425  pthread_attr_t attributes;
    426  pthread_attr_init(&attributes);
    427  return base::GetDefaultThreadStackSize(attributes);
    428 }
    429 
    430 }  // namespace base