tor-browser

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

platform-macos.cpp (7586B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include <unistd.h>
      8 #include <sys/mman.h>
      9 #include <mach/mach_init.h>
     10 #include <mach-o/getsect.h>
     11 
     12 #include <AvailabilityMacros.h>
     13 
     14 #include <pthread.h>
     15 #include <semaphore.h>
     16 #include <signal.h>
     17 #include <libkern/OSAtomic.h>
     18 #include <mach/mach.h>
     19 #include <mach/semaphore.h>
     20 #include <mach/task.h>
     21 #include <mach/thread_act.h>
     22 #include <mach/vm_statistics.h>
     23 #include <sys/time.h>
     24 #include <sys/resource.h>
     25 #include <sys/syscall.h>
     26 #include <sys/types.h>
     27 #include <sys/sysctl.h>
     28 #include <string.h>
     29 #include <errno.h>
     30 #include <math.h>
     31 
     32 // this port is based off of v8 svn revision 9837
     33 
     34 namespace mozilla {
     35 namespace baseprofiler {
     36 
     37 static int64_t MicrosecondsSince1970() {
     38  struct timeval tv;
     39  gettimeofday(&tv, NULL);
     40  return int64_t(tv.tv_sec) * 1000000 + int64_t(tv.tv_usec);
     41 }
     42 
     43 void* GetStackTop(void* aGuess) {
     44  pthread_t thread = pthread_self();
     45  return pthread_get_stackaddr_np(thread);
     46 }
     47 
     48 class PlatformData {
     49 public:
     50  explicit PlatformData(BaseProfilerThreadId aThreadId)
     51      : mProfiledThread(mach_thread_self()) {}
     52 
     53  ~PlatformData() {
     54    // Deallocate Mach port for thread.
     55    mach_port_deallocate(mach_task_self(), mProfiledThread);
     56  }
     57 
     58  thread_act_t ProfiledThread() { return mProfiledThread; }
     59 
     60 private:
     61  // Note: for mProfiledThread Mach primitives are used instead of pthread's
     62  // because the latter doesn't provide thread manipulation primitives required.
     63  // For details, consult "Mac OS X Internals" book, Section 7.3.
     64  thread_act_t mProfiledThread;
     65 };
     66 
     67 ////////////////////////////////////////////////////////////////////////
     68 // BEGIN Sampler target specifics
     69 
     70 Sampler::Sampler(PSLockRef aLock) {}
     71 
     72 void Sampler::Disable(PSLockRef aLock) {}
     73 
     74 template <typename Func>
     75 void Sampler::SuspendAndSampleAndResumeThread(
     76    PSLockRef aLock, const RegisteredThread& aRegisteredThread,
     77    const TimeStamp& aNow, const Func& aProcessRegs) {
     78  thread_act_t samplee_thread =
     79      aRegisteredThread.GetPlatformData()->ProfiledThread();
     80 
     81  //----------------------------------------------------------------//
     82  // Suspend the samplee thread and get its context.
     83 
     84  // We're using thread_suspend on OS X because pthread_kill (which is what we
     85  // at one time used on Linux) has less consistent performance and causes
     86  // strange crashes, see bug 1166778 and bug 1166808.  thread_suspend
     87  // is also just a lot simpler to use.
     88 
     89  if (KERN_SUCCESS != thread_suspend(samplee_thread)) {
     90    return;
     91  }
     92 
     93  //----------------------------------------------------------------//
     94  // Sample the target thread.
     95 
     96  // WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
     97  //
     98  // The profiler's "critical section" begins here.  We must be very careful
     99  // what we do here, or risk deadlock.  See the corresponding comment in
    100  // platform-linux-android.cpp for details.
    101 
    102 #if defined(__x86_64__)
    103  thread_state_flavor_t flavor = x86_THREAD_STATE64;
    104  x86_thread_state64_t state;
    105  mach_msg_type_number_t count = x86_THREAD_STATE64_COUNT;
    106 #  if __DARWIN_UNIX03
    107 #    define REGISTER_FIELD(name) __r##name
    108 #  else
    109 #    define REGISTER_FIELD(name) r##name
    110 #  endif  // __DARWIN_UNIX03
    111 #elif defined(__aarch64__)
    112  thread_state_flavor_t flavor = ARM_THREAD_STATE64;
    113  arm_thread_state64_t state;
    114  mach_msg_type_number_t count = ARM_THREAD_STATE64_COUNT;
    115 #  if __DARWIN_UNIX03
    116 #    define REGISTER_FIELD(name) __##name
    117 #  else
    118 #    define REGISTER_FIELD(name) name
    119 #  endif  // __DARWIN_UNIX03
    120 #else
    121 #  error "unknown architecture"
    122 #endif
    123 
    124  if (thread_get_state(samplee_thread, flavor,
    125                       reinterpret_cast<natural_t*>(&state),
    126                       &count) == KERN_SUCCESS) {
    127    Registers regs;
    128 #if defined(__x86_64__)
    129    regs.mPC = reinterpret_cast<Address>(state.REGISTER_FIELD(ip));
    130    regs.mSP = reinterpret_cast<Address>(state.REGISTER_FIELD(sp));
    131    regs.mFP = reinterpret_cast<Address>(state.REGISTER_FIELD(bp));
    132    regs.mR10 = reinterpret_cast<Address>(state.REGISTER_FIELD(10));
    133    regs.mR12 = reinterpret_cast<Address>(state.REGISTER_FIELD(12));
    134 #elif defined(__aarch64__)
    135    regs.mPC = reinterpret_cast<Address>(state.REGISTER_FIELD(pc));
    136    regs.mSP = reinterpret_cast<Address>(state.REGISTER_FIELD(sp));
    137    regs.mFP = reinterpret_cast<Address>(state.REGISTER_FIELD(fp));
    138    regs.mLR = reinterpret_cast<Address>(state.REGISTER_FIELD(lr));
    139    regs.mR11 = reinterpret_cast<Address>(state.REGISTER_FIELD(x[11]));
    140 #else
    141 #  error "unknown architecture"
    142 #endif
    143 
    144    aProcessRegs(regs, aNow);
    145  }
    146 
    147 #undef REGISTER_FIELD
    148 
    149  //----------------------------------------------------------------//
    150  // Resume the target thread.
    151 
    152  thread_resume(samplee_thread);
    153 
    154  // The profiler's critical section ends here.
    155  //
    156  // WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
    157 }
    158 
    159 // END Sampler target specifics
    160 ////////////////////////////////////////////////////////////////////////
    161 
    162 ////////////////////////////////////////////////////////////////////////
    163 // BEGIN SamplerThread target specifics
    164 
    165 static void* ThreadEntry(void* aArg) {
    166  auto thread = static_cast<SamplerThread*>(aArg);
    167  thread->Run();
    168  return nullptr;
    169 }
    170 
    171 SamplerThread::SamplerThread(PSLockRef aLock, uint32_t aActivityGeneration,
    172                             double aIntervalMilliseconds, uint32_t aFeatures)
    173    : mSampler(aLock),
    174      mActivityGeneration(aActivityGeneration),
    175      mIntervalMicroseconds(
    176          std::max(1, int(floor(aIntervalMilliseconds * 1000 + 0.5)))),
    177      mThread{nullptr} {
    178  pthread_attr_t* attr_ptr = nullptr;
    179  if (pthread_create(&mThread, attr_ptr, ThreadEntry, this) != 0) {
    180    MOZ_CRASH("pthread_create failed");
    181  }
    182 }
    183 
    184 SamplerThread::~SamplerThread() { pthread_join(mThread, nullptr); }
    185 
    186 void SamplerThread::SleepMicro(uint32_t aMicroseconds) {
    187  usleep(aMicroseconds);
    188  // FIXME: the OSX 10.12 page for usleep says "The usleep() function is
    189  // obsolescent.  Use nanosleep(2) instead."  This implementation could be
    190  // merged with the linux-android version.  Also, this doesn't handle the
    191  // case where the usleep call is interrupted by a signal.
    192 }
    193 
    194 void SamplerThread::Stop(PSLockRef aLock) { mSampler.Disable(aLock); }
    195 
    196 // END SamplerThread target specifics
    197 ////////////////////////////////////////////////////////////////////////
    198 
    199 static void PlatformInit(PSLockRef aLock) {}
    200 
    201 // clang-format off
    202 #if defined(HAVE_NATIVE_UNWIND)
    203 // Derive the stack pointer from the frame pointer. The 0x10 offset is
    204 // 8 bytes for the previous frame pointer and 8 bytes for the return
    205 // address both stored on the stack after at the beginning of the current
    206 // frame.
    207 #  define REGISTERS_SYNC_POPULATE(regs)                                       \
    208    regs.mSP = reinterpret_cast<Address>(__builtin_frame_address(0)) + 0x10;  \
    209    _Pragma("GCC diagnostic push")                                            \
    210    _Pragma("GCC diagnostic ignored \"-Wframe-address\"")                     \
    211    regs.mFP = reinterpret_cast<Address>(__builtin_frame_address(1));         \
    212    _Pragma("GCC diagnostic pop")                                             \
    213    regs.mPC = reinterpret_cast<Address>(                                     \
    214        __builtin_extract_return_addr(__builtin_return_address(0)));
    215 #endif
    216 // clang-format on
    217 
    218 }  // namespace baseprofiler
    219 }  // namespace mozilla