LCOV - code coverage report
Current view: top level - tools/profiler/core - platform-linux-android.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 21 148 14.2 %
Date: 2017-07-14 16:53:18 Functions: 6 21 28.6 %
Legend: Lines: hit not hit

          Line data    Source code
       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             : // Copyright (c) 2006-2011 The Chromium Authors. All rights reserved.
       4             : //
       5             : // Redistribution and use in source and binary forms, with or without
       6             : // modification, are permitted provided that the following conditions
       7             : // are met:
       8             : //  * Redistributions of source code must retain the above copyright
       9             : //    notice, this list of conditions and the following disclaimer.
      10             : //  * Redistributions in binary form must reproduce the above copyright
      11             : //    notice, this list of conditions and the following disclaimer in
      12             : //    the documentation and/or other materials provided with the
      13             : //    distribution.
      14             : //  * Neither the name of Google, Inc. nor the names of its contributors
      15             : //    may be used to endorse or promote products derived from this
      16             : //    software without specific prior written permission.
      17             : //
      18             : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
      19             : // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
      20             : // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
      21             : // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
      22             : // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
      23             : // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
      24             : // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
      25             : // OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
      26             : // AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
      27             : // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
      28             : // OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      29             : // SUCH DAMAGE.
      30             : 
      31             : // This file is used for both Linux and Android.
      32             : 
      33             : #include <stdio.h>
      34             : #include <math.h>
      35             : 
      36             : #include <pthread.h>
      37             : #include <semaphore.h>
      38             : #include <signal.h>
      39             : #include <sys/time.h>
      40             : #include <sys/resource.h>
      41             : #include <sys/syscall.h>
      42             : #include <sys/types.h>
      43             : #include <stdlib.h>
      44             : #include <sched.h>
      45             : #include <ucontext.h>
      46             : // Ubuntu Dapper requires memory pages to be marked as
      47             : // executable. Otherwise, OS raises an exception when executing code
      48             : // in that page.
      49             : #include <sys/types.h>  // mmap & munmap
      50             : #include <sys/mman.h>   // mmap & munmap
      51             : #include <sys/stat.h>   // open
      52             : #include <fcntl.h>      // open
      53             : #include <unistd.h>     // sysconf
      54             : #include <semaphore.h>
      55             : #ifdef __GLIBC__
      56             : #include <execinfo.h>   // backtrace, backtrace_symbols
      57             : #endif  // def __GLIBC__
      58             : #include <strings.h>    // index
      59             : #include <errno.h>
      60             : #include <stdarg.h>
      61             : 
      62             : #include "prenv.h"
      63             : #include "mozilla/LinuxSignal.h"
      64             : #include "mozilla/PodOperations.h"
      65             : #include "mozilla/DebugOnly.h"
      66             : 
      67             : #include <string.h>
      68             : #include <list>
      69             : 
      70             : using namespace mozilla;
      71             : 
      72             : /* static */ Thread::tid_t
      73         151 : Thread::GetCurrentId()
      74             : {
      75         151 :   return gettid();
      76             : }
      77             : 
      78             : static void
      79           0 : PopulateRegsFromContext(Registers& aRegs, ucontext_t* aContext)
      80             : {
      81           0 :   aRegs.mContext = aContext;
      82           0 :   mcontext_t& mcontext = aContext->uc_mcontext;
      83             : 
      84             :   // Extracting the sample from the context is extremely machine dependent.
      85             : #if defined(GP_ARCH_x86)
      86             :   aRegs.mPC = reinterpret_cast<Address>(mcontext.gregs[REG_EIP]);
      87             :   aRegs.mSP = reinterpret_cast<Address>(mcontext.gregs[REG_ESP]);
      88             :   aRegs.mFP = reinterpret_cast<Address>(mcontext.gregs[REG_EBP]);
      89             :   aRegs.mLR = 0;
      90             : #elif defined(GP_ARCH_amd64)
      91           0 :   aRegs.mPC = reinterpret_cast<Address>(mcontext.gregs[REG_RIP]);
      92           0 :   aRegs.mSP = reinterpret_cast<Address>(mcontext.gregs[REG_RSP]);
      93           0 :   aRegs.mFP = reinterpret_cast<Address>(mcontext.gregs[REG_RBP]);
      94           0 :   aRegs.mLR = 0;
      95             : #elif defined(GP_ARCH_arm)
      96             :   aRegs.mPC = reinterpret_cast<Address>(mcontext.arm_pc);
      97             :   aRegs.mSP = reinterpret_cast<Address>(mcontext.arm_sp);
      98             :   aRegs.mFP = reinterpret_cast<Address>(mcontext.arm_fp);
      99             :   aRegs.mLR = reinterpret_cast<Address>(mcontext.arm_lr);
     100             : #elif defined(GP_ARCH_aarch64)
     101             :   aRegs.mPC = reinterpret_cast<Address>(mcontext.pc);
     102             :   aRegs.mSP = reinterpret_cast<Address>(mcontext.sp);
     103             :   aRegs.mFP = reinterpret_cast<Address>(mcontext.regs[29]);
     104             :   aRegs.mLR = reinterpret_cast<Address>(mcontext.regs[30]);
     105             : #else
     106             : # error "bad platform"
     107             : #endif
     108           0 : }
     109             : 
     110             : #if defined(GP_OS_android)
     111             : # define SYS_tgkill __NR_tgkill
     112             : #endif
     113             : 
     114             : int
     115           0 : tgkill(pid_t tgid, pid_t tid, int signalno)
     116             : {
     117           0 :   return syscall(SYS_tgkill, tgid, tid, signalno);
     118             : }
     119             : 
     120             : class PlatformData
     121             : {
     122             : public:
     123          75 :   explicit PlatformData(int aThreadId)
     124             :   {
     125          75 :     MOZ_COUNT_CTOR(PlatformData);
     126          75 :   }
     127             : 
     128           1 :   ~PlatformData()
     129             :   {
     130           1 :     MOZ_COUNT_DTOR(PlatformData);
     131           1 :   }
     132             : };
     133             : 
     134             : ////////////////////////////////////////////////////////////////////////
     135             : // BEGIN Sampler target specifics
     136             : 
     137             : // The only way to reliably interrupt a Linux thread and inspect its register
     138             : // and stack state is by sending a signal to it, and doing the work inside the
     139             : // signal handler.  But we don't want to run much code inside the signal
     140             : // handler, since POSIX severely restricts what we can do in signal handlers.
     141             : // So we use a system of semaphores to suspend the thread and allow the
     142             : // sampler thread to do all the work of unwinding and copying out whatever
     143             : // data it wants.
     144             : //
     145             : // A four-message protocol is used to reliably suspend and later resume the
     146             : // thread to be sampled (the samplee):
     147             : //
     148             : // Sampler (signal sender) thread              Samplee (thread to be sampled)
     149             : //
     150             : // Prepare the SigHandlerCoordinator
     151             : // and point sSigHandlerCoordinator at it
     152             : //
     153             : // send SIGPROF to samplee ------- MSG 1 ----> (enter signal handler)
     154             : // wait(mMessage2)                             Copy register state
     155             : //                                               into sSigHandlerCoordinator
     156             : //                         <------ MSG 2 ----- post(mMessage2)
     157             : // Samplee is now suspended.                   wait(mMessage3)
     158             : //   Examine its stack/register
     159             : //   state at leisure
     160             : //
     161             : // Release samplee:
     162             : //   post(mMessage3)       ------- MSG 3 ----->
     163             : // wait(mMessage4)                              Samplee now resumes.  Tell
     164             : //                                                the sampler that we are done.
     165             : //                         <------ MSG 4 ------ post(mMessage4)
     166             : // Now we know the samplee's signal             (leave signal handler)
     167             : //   handler has finished using
     168             : //   sSigHandlerCoordinator.  We can
     169             : //   safely reuse it for some other thread.
     170             : //
     171             : 
     172             : // A type used to coordinate between the sampler (signal sending) thread and
     173             : // the thread currently being sampled (the samplee, which receives the
     174             : // signals).
     175             : //
     176             : // The first message is sent using a SIGPROF signal delivery.  The subsequent
     177             : // three are sent using sem_wait/sem_post pairs.  They are named accordingly
     178             : // in the following struct.
     179             : struct SigHandlerCoordinator
     180             : {
     181           0 :   SigHandlerCoordinator()
     182           0 :   {
     183           0 :     PodZero(&mUContext);
     184           0 :     int r = sem_init(&mMessage2, /* pshared */ 0, 0);
     185           0 :     r    |= sem_init(&mMessage3, /* pshared */ 0, 0);
     186           0 :     r    |= sem_init(&mMessage4, /* pshared */ 0, 0);
     187           0 :     MOZ_ASSERT(r == 0);
     188           0 :   }
     189             : 
     190           0 :   ~SigHandlerCoordinator()
     191           0 :   {
     192           0 :     int r = sem_destroy(&mMessage2);
     193           0 :     r    |= sem_destroy(&mMessage3);
     194           0 :     r    |= sem_destroy(&mMessage4);
     195           0 :     MOZ_ASSERT(r == 0);
     196           0 :   }
     197             : 
     198             :   sem_t mMessage2; // To sampler: "context is in sSigHandlerCoordinator"
     199             :   sem_t mMessage3; // To samplee: "resume"
     200             :   sem_t mMessage4; // To sampler: "finished with sSigHandlerCoordinator"
     201             :   ucontext_t mUContext; // Context at signal
     202             : };
     203             : 
     204             : struct SigHandlerCoordinator* Sampler::sSigHandlerCoordinator = nullptr;
     205             : 
     206             : static void
     207           0 : SigprofHandler(int aSignal, siginfo_t* aInfo, void* aContext)
     208             : {
     209             :   // Avoid TSan warning about clobbering errno.
     210           0 :   int savedErrno = errno;
     211             : 
     212           0 :   MOZ_ASSERT(aSignal == SIGPROF);
     213           0 :   MOZ_ASSERT(Sampler::sSigHandlerCoordinator);
     214             : 
     215             :   // By sending us this signal, the sampler thread has sent us message 1 in
     216             :   // the comment above, with the meaning "|sSigHandlerCoordinator| is ready
     217             :   // for use, please copy your register context into it."
     218           0 :   Sampler::sSigHandlerCoordinator->mUContext =
     219           0 :     *static_cast<ucontext_t*>(aContext);
     220             : 
     221             :   // Send message 2: tell the sampler thread that the context has been copied
     222             :   // into |sSigHandlerCoordinator->mUContext|.  sem_post can never fail by
     223             :   // being interrupted by a signal, so there's no loop around this call.
     224           0 :   int r = sem_post(&Sampler::sSigHandlerCoordinator->mMessage2);
     225           0 :   MOZ_ASSERT(r == 0);
     226             : 
     227             :   // At this point, the sampler thread assumes we are suspended, so we must
     228             :   // not touch any global state here.
     229             : 
     230             :   // Wait for message 3: the sampler thread tells us to resume.
     231             :   while (true) {
     232           0 :     r = sem_wait(&Sampler::sSigHandlerCoordinator->mMessage3);
     233           0 :     if (r == -1 && errno == EINTR) {
     234             :       // Interrupted by a signal.  Try again.
     235           0 :       continue;
     236             :     }
     237             :     // We don't expect any other kind of failure
     238           0 :     MOZ_ASSERT(r == 0);
     239           0 :     break;
     240             :   }
     241             : 
     242             :   // Send message 4: tell the sampler thread that we are finished accessing
     243             :   // |sSigHandlerCoordinator|.  After this point it is not safe to touch
     244             :   // |sSigHandlerCoordinator|.
     245           0 :   r = sem_post(&Sampler::sSigHandlerCoordinator->mMessage4);
     246           0 :   MOZ_ASSERT(r == 0);
     247             : 
     248           0 :   errno = savedErrno;
     249           0 : }
     250             : 
     251           0 : Sampler::Sampler(PSLockRef aLock)
     252           0 :   : mMyPid(getpid())
     253             :   // We don't know what the sampler thread's ID will be until it runs, so set
     254             :   // mSamplerTid to a dummy value and fill it in for real in
     255             :   // SuspendAndSampleAndResumeThread().
     256           0 :   , mSamplerTid(-1)
     257             : {
     258             : #if defined(USE_EHABI_STACKWALK)
     259             :   mozilla::EHABIStackWalkInit();
     260             : #elif defined(USE_LUL_STACKWALK)
     261           0 :   bool createdLUL = false;
     262           0 :   lul::LUL* lul = CorePS::Lul(aLock);
     263           0 :   if (!lul) {
     264           0 :     CorePS::SetLul(aLock, MakeUnique<lul::LUL>(logging_sink_for_LUL));
     265             :     // Read all the unwind info currently available.
     266           0 :     lul = CorePS::Lul(aLock);
     267           0 :     read_procmaps(lul);
     268           0 :     createdLUL = true;
     269             :   }
     270             : #endif
     271             : 
     272             :   // Request profiling signals.
     273             :   struct sigaction sa;
     274           0 :   sa.sa_sigaction = MOZ_SIGNAL_TRAMPOLINE(SigprofHandler);
     275           0 :   sigemptyset(&sa.sa_mask);
     276           0 :   sa.sa_flags = SA_RESTART | SA_SIGINFO;
     277           0 :   if (sigaction(SIGPROF, &sa, &mOldSigprofHandler) != 0) {
     278           0 :     MOZ_CRASH("Error installing SIGPROF handler in the profiler");
     279             :   }
     280             : 
     281             : #if defined(USE_LUL_STACKWALK)
     282           0 :   if (createdLUL) {
     283             :     // Switch into unwind mode. After this point, we can't add or remove any
     284             :     // unwind info to/from this LUL instance. The only thing we can do with
     285             :     // it is Unwind() calls.
     286           0 :     lul->EnableUnwinding();
     287             : 
     288             :     // Has a test been requested?
     289           0 :     if (PR_GetEnv("MOZ_PROFILER_LUL_TEST")) {
     290           0 :       int nTests = 0, nTestsPassed = 0;
     291           0 :       RunLulUnitTests(&nTests, &nTestsPassed, lul);
     292             :     }
     293             :   }
     294             : #endif
     295           0 : }
     296             : 
     297             : void
     298           0 : Sampler::Disable(PSLockRef aLock)
     299             : {
     300             :   // Restore old signal handler. This is global state so it's important that
     301             :   // we do it now, while gPSMutex is locked.
     302           0 :   sigaction(SIGPROF, &mOldSigprofHandler, 0);
     303           0 : }
     304             : 
     305             : template<typename Func>
     306             : void
     307           0 : Sampler::SuspendAndSampleAndResumeThread(PSLockRef aLock,
     308             :                                          const ThreadInfo& aThreadInfo,
     309             :                                          const Func& aProcessRegs)
     310             : {
     311             :   // Only one sampler thread can be sampling at once.  So we expect to have
     312             :   // complete control over |sSigHandlerCoordinator|.
     313           0 :   MOZ_ASSERT(!sSigHandlerCoordinator);
     314             : 
     315           0 :   if (mSamplerTid == -1) {
     316           0 :     mSamplerTid = gettid();
     317             :   }
     318           0 :   int sampleeTid = aThreadInfo.ThreadId();
     319           0 :   MOZ_RELEASE_ASSERT(sampleeTid != mSamplerTid);
     320             : 
     321             :   //----------------------------------------------------------------//
     322             :   // Suspend the samplee thread and get its context.
     323             : 
     324           0 :   SigHandlerCoordinator coord;   // on sampler thread's stack
     325           0 :   sSigHandlerCoordinator = &coord;
     326             : 
     327             :   // Send message 1 to the samplee (the thread to be sampled), by
     328             :   // signalling at it.
     329           0 :   int r = tgkill(mMyPid, sampleeTid, SIGPROF);
     330           0 :   MOZ_ASSERT(r == 0);
     331             : 
     332             :   // Wait for message 2 from the samplee, indicating that the context
     333             :   // is available and that the thread is suspended.
     334             :   while (true) {
     335           0 :     r = sem_wait(&sSigHandlerCoordinator->mMessage2);
     336           0 :     if (r == -1 && errno == EINTR) {
     337             :       // Interrupted by a signal.  Try again.
     338           0 :       continue;
     339             :     }
     340             :     // We don't expect any other kind of failure.
     341           0 :     MOZ_ASSERT(r == 0);
     342           0 :     break;
     343             :   }
     344             : 
     345             :   //----------------------------------------------------------------//
     346             :   // Sample the target thread.
     347             : 
     348             :   // WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
     349             :   //
     350             :   // The profiler's "critical section" begins here.  In the critical section,
     351             :   // we must not do any dynamic memory allocation, nor try to acquire any lock
     352             :   // or any other unshareable resource.  This is because the thread to be
     353             :   // sampled has been suspended at some entirely arbitrary point, and we have
     354             :   // no idea which unsharable resources (locks, essentially) it holds.  So any
     355             :   // attempt to acquire any lock, including the implied locks used by the
     356             :   // malloc implementation, risks deadlock.  This includes TimeStamp::Now(),
     357             :   // which gets a lock on Windows.
     358             : 
     359             :   // The samplee thread is now frozen and sSigHandlerCoordinator->mUContext is
     360             :   // valid.  We can poke around in it and unwind its stack as we like.
     361             : 
     362             :   // Extract the current register values.
     363           0 :   Registers regs;
     364           0 :   PopulateRegsFromContext(regs, &sSigHandlerCoordinator->mUContext);
     365           0 :   aProcessRegs(regs);
     366             : 
     367             :   //----------------------------------------------------------------//
     368             :   // Resume the target thread.
     369             : 
     370             :   // Send message 3 to the samplee, which tells it to resume.
     371           0 :   r = sem_post(&sSigHandlerCoordinator->mMessage3);
     372           0 :   MOZ_ASSERT(r == 0);
     373             : 
     374             :   // Wait for message 4 from the samplee, which tells us that it has
     375             :   // finished with |sSigHandlerCoordinator|.
     376             :   while (true) {
     377           0 :     r = sem_wait(&sSigHandlerCoordinator->mMessage4);
     378           0 :     if (r == -1 && errno == EINTR) {
     379           0 :       continue;
     380             :     }
     381           0 :     MOZ_ASSERT(r == 0);
     382           0 :     break;
     383             :    }
     384             : 
     385             :   // The profiler's critical section ends here.  After this point, none of the
     386             :   // critical section limitations documented above apply.
     387             :   //
     388             :   // WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
     389             : 
     390             :   // This isn't strictly necessary, but doing so does help pick up anomalies
     391             :   // in which the signal handler is running when it shouldn't be.
     392           0 :   sSigHandlerCoordinator = nullptr;
     393           0 : }
     394             : 
     395             : // END Sampler target specifics
     396             : ////////////////////////////////////////////////////////////////////////
     397             : 
     398             : ////////////////////////////////////////////////////////////////////////
     399             : // BEGIN SamplerThread target specifics
     400             : 
     401             : static void*
     402           0 : ThreadEntry(void* aArg)
     403             : {
     404           0 :   auto thread = static_cast<SamplerThread*>(aArg);
     405           0 :   thread->Run();
     406           0 :   return nullptr;
     407             : }
     408             : 
     409           0 : SamplerThread::SamplerThread(PSLockRef aLock, uint32_t aActivityGeneration,
     410           0 :                              double aIntervalMilliseconds)
     411             :   : Sampler(aLock)
     412             :   , mActivityGeneration(aActivityGeneration)
     413             :   , mIntervalMicroseconds(
     414           0 :       std::max(1, int(floor(aIntervalMilliseconds * 1000 + 0.5))))
     415             : {
     416             :   // Start the sampling thread. It repeatedly sends a SIGPROF signal. Sending
     417             :   // the signal ourselves instead of relying on itimer provides much better
     418             :   // accuracy.
     419           0 :   if (pthread_create(&mThread, nullptr, ThreadEntry, this) != 0) {
     420           0 :     MOZ_CRASH("pthread_create failed");
     421             :   }
     422           0 : }
     423             : 
     424           0 : SamplerThread::~SamplerThread()
     425             : {
     426           0 :   pthread_join(mThread, nullptr);
     427           0 : }
     428             : 
     429             : void
     430           0 : SamplerThread::SleepMicro(uint32_t aMicroseconds)
     431             : {
     432           0 :   if (aMicroseconds >= 1000000) {
     433             :     // Use usleep for larger intervals, because the nanosleep
     434             :     // code below only supports intervals < 1 second.
     435           0 :     MOZ_ALWAYS_TRUE(!::usleep(aMicroseconds));
     436           0 :     return;
     437             :   }
     438             : 
     439             :   struct timespec ts;
     440           0 :   ts.tv_sec  = 0;
     441           0 :   ts.tv_nsec = aMicroseconds * 1000UL;
     442             : 
     443           0 :   int rv = ::nanosleep(&ts, &ts);
     444             : 
     445           0 :   while (rv != 0 && errno == EINTR) {
     446             :     // Keep waiting in case of interrupt.
     447             :     // nanosleep puts the remaining time back into ts.
     448           0 :     rv = ::nanosleep(&ts, &ts);
     449             :   }
     450             : 
     451           0 :   MOZ_ASSERT(!rv, "nanosleep call failed");
     452             : }
     453             : 
     454             : void
     455           0 : SamplerThread::Stop(PSLockRef aLock)
     456             : {
     457             :   // Restore old signal handler. This is global state so it's important that
     458             :   // we do it now, while gPSMutex is locked. It's safe to do this now even
     459             :   // though this SamplerThread is still alive, because the next time the main
     460             :   // loop of Run() iterates it won't get past the mActivityGeneration check,
     461             :   // and so won't send any signals.
     462           0 :   Sampler::Disable(aLock);
     463           0 : }
     464             : 
     465             : // END SamplerThread target specifics
     466             : ////////////////////////////////////////////////////////////////////////
     467             : 
     468             : #if defined(GP_OS_linux)
     469             : 
     470             : // We use pthread_atfork() to temporarily disable signal delivery during any
     471             : // fork() call. Without that, fork() can be repeatedly interrupted by signal
     472             : // delivery, requiring it to be repeatedly restarted, which can lead to *long*
     473             : // delays. See bug 837390.
     474             : //
     475             : // We provide no paf_child() function to run in the child after forking. This
     476             : // is fine because we always immediately exec() after fork(), and exec()
     477             : // clobbers all process state. (At one point we did have a paf_child()
     478             : // function, but it caused problems related to locking gPSMutex. See bug
     479             : // 1348374.)
     480             : //
     481             : // Unfortunately all this is only doable on non-Android because Bionic doesn't
     482             : // have pthread_atfork.
     483             : 
     484             : // In the parent, before the fork, record IsPaused, and then pause.
     485             : static void
     486           4 : paf_prepare()
     487             : {
     488           4 :   MOZ_RELEASE_ASSERT(CorePS::Exists());
     489             : 
     490           8 :   PSAutoLock lock(gPSMutex);
     491             : 
     492           4 :   if (ActivePS::Exists(lock)) {
     493           0 :     ActivePS::SetWasPaused(lock, ActivePS::IsPaused(lock));
     494           0 :     ActivePS::SetIsPaused(lock, true);
     495             :   }
     496           4 : }
     497             : 
     498             : // In the parent, after the fork, return IsPaused to the pre-fork state.
     499             : static void
     500           4 : paf_parent()
     501             : {
     502           4 :   MOZ_RELEASE_ASSERT(CorePS::Exists());
     503             : 
     504           8 :   PSAutoLock lock(gPSMutex);
     505             : 
     506           4 :   if (ActivePS::Exists(lock)) {
     507           0 :     ActivePS::SetIsPaused(lock, ActivePS::WasPaused(lock));
     508           0 :     ActivePS::SetWasPaused(lock, false);
     509             :   }
     510           4 : }
     511             : 
     512             : static void
     513           3 : PlatformInit(PSLockRef aLock)
     514             : {
     515             :   // Set up the fork handlers.
     516           3 :   pthread_atfork(paf_prepare, paf_parent, nullptr);
     517           3 : }
     518             : 
     519             : #else
     520             : 
     521             : static void
     522             : PlatformInit(PSLockRef aLock)
     523             : {
     524             : }
     525             : 
     526             : #endif
     527             : 
     528             : #if defined(HAVE_NATIVE_UNWIND)
     529             : // Context used by synchronous samples. It's safe to have a single one because
     530             : // only one synchronous sample can be taken at a time (due to
     531             : // profiler_get_backtrace()'s PSAutoLock).
     532             : ucontext_t sSyncUContext;
     533             : 
     534             : void
     535           0 : Registers::SyncPopulate()
     536             : {
     537           0 :   if (!getcontext(&sSyncUContext)) {
     538           0 :     PopulateRegsFromContext(*this, &sSyncUContext);
     539             :   }
     540           0 : }
     541             : #endif
     542             : 

Generated by: LCOV version 1.13