LCOV - code coverage report
Current view: top level - xpcom/threads - nsTimerImpl.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 150 294 51.0 %
Date: 2017-07-14 16:53:18 Functions: 27 38 71.1 %
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             : /* 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 "nsTimerImpl.h"
       8             : #include "TimerThread.h"
       9             : #include "nsAutoPtr.h"
      10             : #include "nsThreadManager.h"
      11             : #include "nsThreadUtils.h"
      12             : #include "pratom.h"
      13             : #include "GeckoProfiler.h"
      14             : #include "mozilla/Atomics.h"
      15             : #include "mozilla/IntegerPrintfMacros.h"
      16             : #include "mozilla/Logging.h"
      17             : #ifdef MOZ_TASK_TRACER
      18             : #include "GeckoTaskTracerImpl.h"
      19             : using namespace mozilla::tasktracer;
      20             : #endif
      21             : 
      22             : #ifdef XP_WIN
      23             : #include <process.h>
      24             : #ifndef getpid
      25             : #define getpid _getpid
      26             : #endif
      27             : #else
      28             : #include <unistd.h>
      29             : #endif
      30             : 
      31             : using mozilla::Atomic;
      32             : using mozilla::LogLevel;
      33             : using mozilla::TimeDuration;
      34             : using mozilla::TimeStamp;
      35             : 
      36             : static TimerThread*     gThread = nullptr;
      37             : 
      38             : // This module prints info about the precision of timers.
      39             : static mozilla::LazyLogModule sTimerLog("nsTimerImpl");
      40             : 
      41             : mozilla::LogModule*
      42        1015 : GetTimerLog()
      43             : {
      44        1015 :   return sTimerLog;
      45             : }
      46             : 
      47             : TimeStamp
      48         159 : NS_GetTimerDeadlineHintOnCurrentThread(TimeStamp aDefault, uint32_t aSearchBound)
      49             : {
      50             :   return gThread
      51         159 :            ? gThread->FindNextFireTimeForCurrentThread(aDefault, aSearchBound)
      52         318 :            : TimeStamp();
      53             : }
      54             : 
      55             : // This module prints info about which timers are firing, which is useful for
      56             : // wakeups for the purposes of power profiling. Set the following environment
      57             : // variable before starting the browser.
      58             : //
      59             : //   MOZ_LOG=TimerFirings:4
      60             : //
      61             : // Then a line will be printed for every timer that fires. The name used for a
      62             : // |Callback::Type::Function| timer depends on the circumstances.
      63             : //
      64             : // - If it was explicitly named (e.g. it was initialized with
      65             : //   InitWithNamedFuncCallback()) then that explicit name will be shown.
      66             : //
      67             : // - Otherwise, if we are on a platform that supports function name lookup
      68             : //   (Mac or Linux) then the looked-up name will be shown with a
      69             : //   "[from dladdr]" annotation. On Mac the looked-up name will be immediately
      70             : //   useful. On Linux it'll need post-processing with
      71             : //   tools/rb/fix_linux_stack.py.
      72             : //
      73             : // - Otherwise, no name will be printed. If many timers hit this case then
      74             : //   you'll need to re-run the workload on a Mac to find out which timers they
      75             : //   are, and then give them explicit names.
      76             : //
      77             : // If you redirect this output to a file called "out", you can then
      78             : // post-process it with a command something like the following.
      79             : //
      80             : //   cat out | grep timer | sort | uniq -c | sort -r -n
      81             : //
      82             : // This will show how often each unique line appears, with the most common ones
      83             : // first.
      84             : //
      85             : // More detailed docs are here:
      86             : // https://developer.mozilla.org/en-US/docs/Mozilla/Performance/TimerFirings_logging
      87             : //
      88             : static mozilla::LazyLogModule sTimerFiringsLog("TimerFirings");
      89             : 
      90             : mozilla::LogModule*
      91          73 : GetTimerFiringsLog()
      92             : {
      93          73 :   return sTimerFiringsLog;
      94             : }
      95             : 
      96             : #include <math.h>
      97             : 
      98             : double nsTimerImpl::sDeltaSumSquared = 0;
      99             : double nsTimerImpl::sDeltaSum = 0;
     100             : double nsTimerImpl::sDeltaNum = 0;
     101             : 
     102             : static void
     103           0 : myNS_MeanAndStdDev(double n, double sumOfValues, double sumOfSquaredValues,
     104             :                    double* meanResult, double* stdDevResult)
     105             : {
     106           0 :   double mean = 0.0, var = 0.0, stdDev = 0.0;
     107           0 :   if (n > 0.0 && sumOfValues >= 0) {
     108           0 :     mean = sumOfValues / n;
     109           0 :     double temp = (n * sumOfSquaredValues) - (sumOfValues * sumOfValues);
     110           0 :     if (temp < 0.0 || n <= 1) {
     111           0 :       var = 0.0;
     112             :     } else {
     113           0 :       var = temp / (n * (n - 1));
     114             :     }
     115             :     // for some reason, Windows says sqrt(0.0) is "-1.#J" (?!) so do this:
     116           0 :     stdDev = var != 0.0 ? sqrt(var) : 0.0;
     117             :   }
     118           0 :   *meanResult = mean;
     119           0 :   *stdDevResult = stdDev;
     120           0 : }
     121             : 
     122         654 : NS_IMPL_QUERY_INTERFACE(nsTimer, nsITimer)
     123        1060 : NS_IMPL_ADDREF(nsTimer)
     124             : 
     125             : NS_IMETHODIMP_(MozExternalRefCountType)
     126         771 : nsTimer::Release(void)
     127             : {
     128         771 :   nsrefcnt count = --mRefCnt;
     129         771 :   NS_LOG_RELEASE(this, count, "nsTimer");
     130             : 
     131         771 :   if (count == 1) {
     132          83 :     if (!mImpl->CancelCheckIfFiring()) {
     133             :       // Last ref, in nsTimerImpl::mITimer. Make sure the cycle is broken.
     134             :       // (when Cancel fails, nsTimerImpl::Fire is in progress, which has grabbed
     135             :       // another ref to the nsITimer since we checked the value of mRefCnt
     136             :       // above)
     137             :       // If there is a nsTimerEvent in a queue for this timer, the nsTimer will
     138             :       // live until that event pops, otherwise the nsTimerImpl will go away and
     139             :       // the nsTimer along with it.
     140          83 :       mImpl = nullptr;
     141             :     }
     142         688 :   } else if (count == 0) {
     143          83 :     delete this;
     144             :   }
     145             : 
     146         771 :   return count;
     147             : }
     148             : 
     149         218 : nsTimerImpl::nsTimerImpl(nsITimer* aTimer) :
     150             :   mHolder(nullptr),
     151             :   mGeneration(0),
     152             :   mITimer(aTimer),
     153         218 :   mMutex("nsTimerImpl::mMutex")
     154             : {
     155             :   // XXXbsmedberg: shouldn't this be in Init()?
     156         218 :   mEventTarget = GetCurrentThreadEventTarget();
     157         218 : }
     158             : 
     159             : //static
     160             : nsresult
     161           3 : nsTimerImpl::Startup()
     162             : {
     163             :   nsresult rv;
     164             : 
     165           3 :   gThread = new TimerThread();
     166             : 
     167           3 :   NS_ADDREF(gThread);
     168           3 :   rv = gThread->InitLocks();
     169             : 
     170           3 :   if (NS_FAILED(rv)) {
     171           0 :     NS_RELEASE(gThread);
     172             :   }
     173             : 
     174           3 :   return rv;
     175             : }
     176             : 
     177             : void
     178           0 : nsTimerImpl::Shutdown()
     179             : {
     180           0 :   if (MOZ_LOG_TEST(GetTimerLog(), LogLevel::Debug)) {
     181           0 :     double mean = 0, stddev = 0;
     182           0 :     myNS_MeanAndStdDev(sDeltaNum, sDeltaSum, sDeltaSumSquared, &mean, &stddev);
     183             : 
     184           0 :     MOZ_LOG(GetTimerLog(), LogLevel::Debug,
     185             :            ("sDeltaNum = %f, sDeltaSum = %f, sDeltaSumSquared = %f\n",
     186             :             sDeltaNum, sDeltaSum, sDeltaSumSquared));
     187           0 :     MOZ_LOG(GetTimerLog(), LogLevel::Debug,
     188             :            ("mean: %fms, stddev: %fms\n", mean, stddev));
     189             :   }
     190             : 
     191           0 :   if (!gThread) {
     192           0 :     return;
     193             :   }
     194             : 
     195           0 :   gThread->Shutdown();
     196           0 :   NS_RELEASE(gThread);
     197             : }
     198             : 
     199             : nsresult
     200         208 : nsTimerImpl::InitCommon(uint32_t aDelayMS, uint32_t aType,
     201             :                         Callback&& aNewCallback)
     202             : {
     203         416 :   return InitCommon(TimeDuration::FromMilliseconds(aDelayMS),
     204         624 :                     aType, Move(aNewCallback));
     205             : }
     206             : 
     207             : 
     208             : nsresult
     209         288 : nsTimerImpl::InitCommon(const TimeDuration& aDelay, uint32_t aType,
     210             :                         Callback&& newCallback)
     211             : {
     212         288 :   mMutex.AssertCurrentThreadOwns();
     213             : 
     214         288 :   if (NS_WARN_IF(!gThread)) {
     215           0 :     return NS_ERROR_NOT_INITIALIZED;
     216             :   }
     217             : 
     218         288 :   if (!mEventTarget) {
     219           0 :     NS_ERROR("mEventTarget is NULL");
     220           0 :     return NS_ERROR_NOT_INITIALIZED;
     221             :   }
     222             : 
     223         288 :   gThread->RemoveTimer(this);
     224         288 :   mCallback.swap(newCallback);
     225         288 :   ++mGeneration;
     226             : 
     227         288 :   mType = (uint8_t)aType;
     228         288 :   mDelay = aDelay;
     229         288 :   mTimeout = TimeStamp::Now() + mDelay;
     230             : 
     231         288 :   return gThread->AddTimer(this);
     232             : }
     233             : 
     234             : nsresult
     235         199 : nsTimerImpl::InitWithFuncCallbackCommon(nsTimerCallbackFunc aFunc,
     236             :                                         void* aClosure,
     237             :                                         uint32_t aDelay,
     238             :                                         uint32_t aType,
     239             :                                         const Callback::Name& aName)
     240             : {
     241         199 :   if (NS_WARN_IF(!aFunc)) {
     242           0 :     return NS_ERROR_INVALID_ARG;
     243             :   }
     244             : 
     245         398 :   Callback cb; // Goes out of scope after the unlock, prevents deadlock
     246         199 :   cb.mType = Callback::Type::Function;
     247         199 :   cb.mCallback.c = aFunc;
     248         199 :   cb.mClosure = aClosure;
     249         199 :   cb.mName = aName;
     250             : 
     251         398 :   MutexAutoLock lock(mMutex);
     252         199 :   return InitCommon(aDelay, aType, mozilla::Move(cb));
     253             : }
     254             : 
     255             : nsresult
     256         199 : nsTimerImpl::InitWithNamedFuncCallback(nsTimerCallbackFunc aFunc,
     257             :                                        void* aClosure,
     258             :                                        uint32_t aDelay,
     259             :                                        uint32_t aType,
     260             :                                        const char* aNameString)
     261             : {
     262         398 :   Callback::Name name(aNameString);
     263         398 :   return InitWithFuncCallbackCommon(aFunc, aClosure, aDelay, aType, name);
     264             : }
     265             : 
     266             : nsresult
     267           0 : nsTimerImpl::InitWithNameableFuncCallback(nsTimerCallbackFunc aFunc,
     268             :                                           void* aClosure,
     269             :                                           uint32_t aDelay,
     270             :                                           uint32_t aType,
     271             :                                           nsTimerNameCallbackFunc aNameFunc)
     272             : {
     273           0 :   Callback::Name name(aNameFunc);
     274           0 :   return InitWithFuncCallbackCommon(aFunc, aClosure, aDelay, aType, name);
     275             : }
     276             : 
     277             : nsresult
     278          70 : nsTimerImpl::InitWithCallback(nsITimerCallback* aCallback,
     279             :                               uint32_t aDelay,
     280             :                               uint32_t aType)
     281             : {
     282             :   return InitHighResolutionWithCallback(aCallback,
     283         140 :                                         TimeDuration::FromMilliseconds(aDelay),
     284         140 :                                         aType);
     285             : }
     286             : 
     287             : nsresult
     288          80 : nsTimerImpl::InitHighResolutionWithCallback(nsITimerCallback* aCallback,
     289             :                                             const TimeDuration& aDelay,
     290             :                                             uint32_t aType)
     291             : {
     292          80 :   if (NS_WARN_IF(!aCallback)) {
     293           0 :     return NS_ERROR_INVALID_ARG;
     294             :   }
     295             : 
     296         160 :   Callback cb; // Goes out of scope after the unlock, prevents deadlock
     297          80 :   cb.mType = Callback::Type::Interface;
     298          80 :   cb.mCallback.i = aCallback;
     299          80 :   NS_ADDREF(cb.mCallback.i);
     300             : 
     301         160 :   MutexAutoLock lock(mMutex);
     302          80 :   return InitCommon(aDelay, aType, mozilla::Move(cb));
     303             : }
     304             : 
     305             : nsresult
     306           9 : nsTimerImpl::Init(nsIObserver* aObserver, uint32_t aDelay, uint32_t aType)
     307             : {
     308           9 :   if (NS_WARN_IF(!aObserver)) {
     309           0 :     return NS_ERROR_INVALID_ARG;
     310             :   }
     311             : 
     312          18 :   Callback cb; // Goes out of scope after the unlock, prevents deadlock
     313           9 :   cb.mType = Callback::Type::Observer;
     314           9 :   cb.mCallback.o = aObserver;
     315           9 :   NS_ADDREF(cb.mCallback.o);
     316             : 
     317          18 :   MutexAutoLock lock(mMutex);
     318           9 :   return InitCommon(aDelay, aType, mozilla::Move(cb));
     319             : }
     320             : 
     321             : bool
     322        1426 : nsTimerImpl::CancelCheckIfFiring()
     323             : {
     324        2852 :   Callback cb;
     325             : 
     326        2852 :   MutexAutoLock lock(mMutex);
     327             : 
     328        1426 :   if (gThread) {
     329        1426 :     gThread->RemoveTimer(this);
     330             :   }
     331             : 
     332        1426 :   cb.swap(mCallback);
     333        1426 :   ++mGeneration;
     334             : 
     335        1426 :   if (mCallbackDuringFire.mType != Callback::Type::Unknown) {
     336          45 :     return true;
     337             :   }
     338        1381 :   return false;
     339             : }
     340             : 
     341             : nsresult
     342        1343 : nsTimerImpl::Cancel()
     343             : {
     344        1343 :   (void)CancelCheckIfFiring();
     345        1343 :   return NS_OK;
     346             : }
     347             : 
     348             : nsresult
     349           0 : nsTimerImpl::SetDelay(uint32_t aDelay)
     350             : {
     351           0 :   MutexAutoLock lock(mMutex);
     352           0 :   if (GetCallback().mType == Callback::Type::Unknown && !IsRepeating()) {
     353             :     // This may happen if someone tries to re-use a one-shot timer
     354             :     // by re-setting delay instead of reinitializing the timer.
     355           0 :     NS_ERROR("nsITimer->SetDelay() called when the "
     356             :              "one-shot timer is not set up.");
     357           0 :     return NS_ERROR_NOT_INITIALIZED;
     358             :   }
     359             : 
     360           0 :   bool reAdd = false;
     361           0 :   if (gThread) {
     362           0 :     reAdd = NS_SUCCEEDED(gThread->RemoveTimer(this));
     363             :   }
     364             : 
     365           0 :   mDelay = TimeDuration::FromMilliseconds(aDelay);
     366           0 :   mTimeout = TimeStamp::Now() + mDelay;
     367             : 
     368           0 :   if (reAdd) {
     369           0 :     gThread->AddTimer(this);
     370             :   }
     371             : 
     372           0 :   return NS_OK;
     373             : }
     374             : 
     375             : nsresult
     376           2 : nsTimerImpl::GetDelay(uint32_t* aDelay)
     377             : {
     378           4 :   MutexAutoLock lock(mMutex);
     379           2 :   *aDelay = mDelay.ToMilliseconds();
     380           4 :   return NS_OK;
     381             : }
     382             : 
     383             : nsresult
     384           0 : nsTimerImpl::SetType(uint32_t aType)
     385             : {
     386           0 :   MutexAutoLock lock(mMutex);
     387           0 :   mType = (uint8_t)aType;
     388             :   // XXX if this is called, we should change the actual type.. this could effect
     389             :   // repeating timers.  we need to ensure in Fire() that if mType has changed
     390             :   // during the callback that we don't end up with the timer in the queue twice.
     391           0 :   return NS_OK;
     392             : }
     393             : 
     394             : nsresult
     395           0 : nsTimerImpl::GetType(uint32_t* aType)
     396             : {
     397           0 :   MutexAutoLock lock(mMutex);
     398           0 :   *aType = mType;
     399           0 :   return NS_OK;
     400             : }
     401             : 
     402             : 
     403             : nsresult
     404           0 : nsTimerImpl::GetClosure(void** aClosure)
     405             : {
     406           0 :   MutexAutoLock lock(mMutex);
     407           0 :   *aClosure = GetCallback().mClosure;
     408           0 :   return NS_OK;
     409             : }
     410             : 
     411             : 
     412             : nsresult
     413           0 : nsTimerImpl::GetCallback(nsITimerCallback** aCallback)
     414             : {
     415           0 :   MutexAutoLock lock(mMutex);
     416           0 :   if (GetCallback().mType == Callback::Type::Interface) {
     417           0 :     NS_IF_ADDREF(*aCallback = GetCallback().mCallback.i);
     418             :   } else {
     419           0 :     *aCallback = nullptr;
     420             :   }
     421             : 
     422           0 :   return NS_OK;
     423             : }
     424             : 
     425             : 
     426             : nsresult
     427           0 : nsTimerImpl::GetTarget(nsIEventTarget** aTarget)
     428             : {
     429           0 :   MutexAutoLock lock(mMutex);
     430           0 :   NS_IF_ADDREF(*aTarget = mEventTarget);
     431           0 :   return NS_OK;
     432             : }
     433             : 
     434             : 
     435             : nsresult
     436         195 : nsTimerImpl::SetTarget(nsIEventTarget* aTarget)
     437             : {
     438         390 :   MutexAutoLock lock(mMutex);
     439         195 :   if (NS_WARN_IF(mCallback.mType != Callback::Type::Unknown)) {
     440           0 :     return NS_ERROR_ALREADY_INITIALIZED;
     441             :   }
     442             : 
     443         195 :   if (aTarget) {
     444         192 :     mEventTarget = aTarget;
     445             :   } else {
     446           3 :     mEventTarget = GetCurrentThreadEventTarget();
     447             :   }
     448         195 :   return NS_OK;
     449             : }
     450             : 
     451             : nsresult
     452           2 : nsTimerImpl::GetAllowedEarlyFiringMicroseconds(uint32_t* aValueOut)
     453             : {
     454           2 :   *aValueOut = gThread ? gThread->AllowedEarlyFiringMicroseconds() : 0;
     455           2 :   return NS_OK;
     456             : }
     457             : 
     458             : void
     459          78 : nsTimerImpl::Fire(int32_t aGeneration)
     460             : {
     461             :   uint8_t oldType;
     462             :   uint32_t oldDelay;
     463          78 :   TimeStamp oldTimeout;
     464         151 :   nsCOMPtr<nsITimer> kungFuDeathGrip;
     465             : 
     466             :   {
     467             :     // Don't fire callbacks or fiddle with refcounts when the mutex is locked.
     468             :     // If some other thread Cancels/Inits after this, they're just too late.
     469         151 :     MutexAutoLock lock(mMutex);
     470          78 :     if (aGeneration != mGeneration) {
     471           5 :       return;
     472             :     }
     473             : 
     474          73 :     mCallbackDuringFire.swap(mCallback);
     475          73 :     oldType = mType;
     476          73 :     oldDelay = mDelay.ToMilliseconds();
     477          73 :     oldTimeout = mTimeout;
     478             :     // Ensure that the nsITimer does not unhook from the nsTimerImpl during
     479             :     // Fire; this will cause null pointer crashes if the user of the timer drops
     480             :     // its reference, and then uses the nsITimer* passed in the callback.
     481          73 :     kungFuDeathGrip = mITimer;
     482             :   }
     483             : 
     484         146 :   AUTO_PROFILER_LABEL("nsTimerImpl::Fire", OTHER);
     485             : 
     486          73 :   TimeStamp now = TimeStamp::Now();
     487          73 :   if (MOZ_LOG_TEST(GetTimerLog(), LogLevel::Debug)) {
     488           0 :     TimeDuration   delta = now - oldTimeout;
     489           0 :     int32_t       d = delta.ToMilliseconds(); // delta in ms
     490           0 :     sDeltaSum += abs(d);
     491           0 :     sDeltaSumSquared += double(d) * double(d);
     492           0 :     sDeltaNum++;
     493             : 
     494           0 :     MOZ_LOG(GetTimerLog(), LogLevel::Debug,
     495             :            ("[this=%p] expected delay time %4ums\n", this, oldDelay));
     496           0 :     MOZ_LOG(GetTimerLog(), LogLevel::Debug,
     497             :            ("[this=%p] actual delay time   %4dms\n", this, oldDelay + d));
     498           0 :     MOZ_LOG(GetTimerLog(), LogLevel::Debug,
     499             :            ("[this=%p] (mType is %d)       -------\n", this, oldType));
     500           0 :     MOZ_LOG(GetTimerLog(), LogLevel::Debug,
     501             :            ("[this=%p]     delta           %4dms\n", this, d));
     502             :   }
     503             : 
     504          73 :   if (MOZ_LOG_TEST(GetTimerFiringsLog(), LogLevel::Debug)) {
     505           0 :     LogFiring(mCallbackDuringFire, oldType, oldDelay);
     506             :   }
     507             : 
     508          73 :   switch (mCallbackDuringFire.mType) {
     509             :     case Callback::Type::Function:
     510          58 :       mCallbackDuringFire.mCallback.c(mITimer, mCallbackDuringFire.mClosure);
     511          58 :       break;
     512             :     case Callback::Type::Interface:
     513          15 :       mCallbackDuringFire.mCallback.i->Notify(mITimer);
     514          15 :       break;
     515             :     case Callback::Type::Observer:
     516           0 :       mCallbackDuringFire.mCallback.o->Observe(mITimer, NS_TIMER_CALLBACK_TOPIC,
     517           0 :                                                nullptr);
     518           0 :       break;
     519             :     default:
     520             :       ;
     521             :   }
     522             : 
     523         146 :   Callback trash; // Swap into here to dispose of callback after the unlock
     524         146 :   MutexAutoLock lock(mMutex);
     525          73 :   if (aGeneration == mGeneration && IsRepeating()) {
     526             :     // Repeating timer has not been re-init or canceled; reschedule
     527          18 :     mCallbackDuringFire.swap(mCallback);
     528          18 :     if (IsSlack()) {
     529          18 :       mTimeout = TimeStamp::Now() + mDelay;
     530             :     } else {
     531           0 :       mTimeout = mTimeout + mDelay;
     532             :     }
     533          18 :     if (gThread) {
     534          18 :       gThread->AddTimer(this);
     535             :     }
     536             :   }
     537             : 
     538          73 :   mCallbackDuringFire.swap(trash);
     539             : 
     540          73 :   MOZ_LOG(GetTimerLog(), LogLevel::Debug,
     541             :          ("[this=%p] Took %fms to fire timer callback\n",
     542             :           this, (TimeStamp::Now() - now).ToMilliseconds()));
     543             : }
     544             : 
     545             : #if defined(HAVE_DLADDR) && defined(HAVE___CXA_DEMANGLE)
     546             : #define USE_DLADDR 1
     547             : #endif
     548             : 
     549             : #ifdef USE_DLADDR
     550             : #include <cxxabi.h>
     551             : #include <dlfcn.h>
     552             : #endif
     553             : 
     554             : // See the big comment above GetTimerFiringsLog() to understand this code.
     555             : void
     556           0 : nsTimerImpl::LogFiring(const Callback& aCallback, uint8_t aType, uint32_t aDelay)
     557             : {
     558             :   const char* typeStr;
     559           0 :   switch (aType) {
     560           0 :     case nsITimer::TYPE_ONE_SHOT:                     typeStr = "ONE_SHOT  "; break;
     561           0 :     case nsITimer::TYPE_ONE_SHOT_LOW_PRIORITY:        typeStr = "ONE_LOW   "; break;
     562           0 :     case nsITimer::TYPE_REPEATING_SLACK:              typeStr = "SLACK     "; break;
     563           0 :     case nsITimer::TYPE_REPEATING_SLACK_LOW_PRIORITY: typeStr = "SLACK_LOW "; break;
     564             :     case nsITimer::TYPE_REPEATING_PRECISE:          /* fall through */
     565           0 :     case nsITimer::TYPE_REPEATING_PRECISE_CAN_SKIP:   typeStr = "PRECISE   "; break;
     566           0 :     default:                              MOZ_CRASH("bad type");
     567             :   }
     568             : 
     569           0 :   switch (aCallback.mType) {
     570             :     case Callback::Type::Function: {
     571           0 :       bool needToFreeName = false;
     572           0 :       const char* annotation = "";
     573             :       const char* name;
     574             :       static const size_t buflen = 1024;
     575             :       char buf[buflen];
     576             : 
     577           0 :       if (aCallback.mName.is<Callback::NameString>()) {
     578           0 :         name = aCallback.mName.as<Callback::NameString>();
     579             : 
     580           0 :       } else if (aCallback.mName.is<Callback::NameFunc>()) {
     581           0 :         aCallback.mName.as<Callback::NameFunc>()(
     582           0 :             mITimer, /* aAnonymize = */ false, aCallback.mClosure, buf, buflen);
     583           0 :         name = buf;
     584             : 
     585             :       } else {
     586           0 :         MOZ_ASSERT(aCallback.mName.is<Callback::NameNothing>());
     587             : #ifdef USE_DLADDR
     588           0 :         annotation = "[from dladdr] ";
     589             : 
     590             :         Dl_info info;
     591           0 :         void* addr = reinterpret_cast<void*>(aCallback.mCallback.c);
     592           0 :         if (dladdr(addr, &info) == 0) {
     593           0 :           name = "???[dladdr: failed]";
     594             : 
     595           0 :         } else if (info.dli_sname) {
     596             :           int status;
     597           0 :           name = abi::__cxa_demangle(info.dli_sname, nullptr, nullptr, &status);
     598           0 :           if (status == 0) {
     599             :             // Success. Because we didn't pass in a buffer to __cxa_demangle it
     600             :             // allocates its own one with malloc() which we must free() later.
     601           0 :             MOZ_ASSERT(name);
     602           0 :             needToFreeName = true;
     603           0 :           } else if (status == -1) {
     604           0 :             name = "???[__cxa_demangle: OOM]";
     605           0 :           } else if (status == -2) {
     606           0 :             name = "???[__cxa_demangle: invalid mangled name]";
     607           0 :           } else if (status == -3) {
     608           0 :             name = "???[__cxa_demangle: invalid argument]";
     609             :           } else {
     610           0 :             name = "???[__cxa_demangle: unexpected status value]";
     611             :           }
     612             : 
     613           0 :         } else if (info.dli_fname) {
     614             :           // The "#0: " prefix is necessary for fix_linux_stack.py to interpret
     615             :           // this string as something to convert.
     616           0 :           snprintf(buf, buflen, "#0: ???[%s +0x%" PRIxPTR "]\n",
     617           0 :                    info.dli_fname, uintptr_t(addr) - uintptr_t(info.dli_fbase));
     618           0 :           name = buf;
     619             : 
     620             :         } else {
     621           0 :           name = "???[dladdr: no symbol or shared object obtained]";
     622             :         }
     623             : #else
     624             :         name = "???[dladdr is unimplemented or doesn't work well on this OS]";
     625             : #endif
     626             :       }
     627             : 
     628           0 :       MOZ_LOG(GetTimerFiringsLog(), LogLevel::Debug,
     629             :               ("[%d]    fn timer (%s %5d ms): %s%s\n",
     630             :                getpid(), typeStr, aDelay, annotation, name));
     631             : 
     632           0 :       if (needToFreeName) {
     633           0 :         free(const_cast<char*>(name));
     634             :       }
     635             : 
     636           0 :       break;
     637             :     }
     638             : 
     639             :     case Callback::Type::Interface: {
     640           0 :       MOZ_LOG(GetTimerFiringsLog(), LogLevel::Debug,
     641             :               ("[%d] iface timer (%s %5d ms): %p\n",
     642             :                getpid(), typeStr, aDelay, aCallback.mCallback.i));
     643           0 :       break;
     644             :     }
     645             : 
     646             :     case Callback::Type::Observer: {
     647           0 :       MOZ_LOG(GetTimerFiringsLog(), LogLevel::Debug,
     648             :               ("[%d]   obs timer (%s %5d ms): %p\n",
     649             :                getpid(), typeStr, aDelay, aCallback.mCallback.o));
     650           0 :       break;
     651             :     }
     652             : 
     653             :     case Callback::Type::Unknown:
     654             :     default: {
     655           0 :       MOZ_LOG(GetTimerFiringsLog(), LogLevel::Debug,
     656             :               ("[%d]   ??? timer (%s, %5d ms)\n",
     657             :                getpid(), typeStr, aDelay));
     658           0 :       break;
     659             :     }
     660             :   }
     661           0 : }
     662             : 
     663             : void
     664          85 : nsTimerImpl::GetName(nsACString& aName)
     665             : {
     666         170 :   MutexAutoLock lock(mMutex);
     667          85 :   Callback& cb(GetCallback());
     668          85 :   switch (cb.mType) {
     669             :     case Callback::Type::Function:
     670          63 :       if (cb.mName.is<Callback::NameString>()) {
     671          63 :         aName.Assign(cb.mName.as<Callback::NameString>());
     672           0 :       } else if (cb.mName.is<Callback::NameFunc>()) {
     673             :         static const size_t buflen = 1024;
     674             :         char buf[buflen];
     675           0 :         cb.mName.as<Callback::NameFunc>()(
     676           0 :             mITimer, /* aAnonymize = */ true, cb.mClosure, buf, buflen);
     677           0 :         aName.Assign(buf);
     678             :       } else {
     679           0 :         MOZ_ASSERT(cb.mName.is<Callback::NameNothing>());
     680           0 :         aName.AssignLiteral("Anonymous_callback_timer");
     681             :       }
     682          63 :       break;
     683             : 
     684             :     case Callback::Type::Interface:
     685          34 :       if (nsCOMPtr<nsINamed> named = do_QueryInterface(cb.mCallback.i)) {
     686           8 :         named->GetName(aName);
     687             :       } else {
     688           9 :         aName.AssignLiteral("Anonymous_interface_timer");
     689             :       }
     690          17 :       break;
     691             : 
     692             :     case Callback::Type::Observer:
     693           0 :       if (nsCOMPtr<nsINamed> named = do_QueryInterface(cb.mCallback.o)) {
     694           0 :         named->GetName(aName);
     695             :       } else {
     696           0 :         aName.AssignLiteral("Anonymous_observer_timer");
     697             :       }
     698           0 :       break;
     699             : 
     700             :     case Callback::Type::Unknown:
     701           5 :       aName.AssignLiteral("Canceled_timer");
     702           5 :       break;
     703             :   }
     704          85 : }
     705             : 
     706             : void
     707         570 : nsTimerImpl::SetHolder(nsTimerImplHolder* aHolder)
     708             : {
     709         570 :   mHolder = aHolder;
     710         570 : }
     711             : 
     712         166 : nsTimer::~nsTimer()
     713             : {
     714         249 : }
     715             : 
     716             : size_t
     717           0 : nsTimer::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
     718             : {
     719           0 :   return aMallocSizeOf(this);
     720             : }
     721             : 
     722             : /* static */
     723           9 : const nsTimerImpl::Callback::NameNothing nsTimerImpl::Callback::Nothing = 0;
     724             : 
     725             : #ifdef MOZ_TASK_TRACER
     726             : void
     727             : nsTimerImpl::GetTLSTraceInfo()
     728             : {
     729             :   mTracedTask.GetTLSTraceInfo();
     730             : }
     731             : 
     732             : TracedTaskCommon
     733             : nsTimerImpl::GetTracedTask()
     734             : {
     735             :   return mTracedTask;
     736             : }
     737             : 
     738             : #endif

Generated by: LCOV version 1.13