LCOV - code coverage report
Current view: top level - xpcom/threads - nsTimerImpl.h (source / functions) Hit Total Coverage
Test: output.info Lines: 54 56 96.4 %
Date: 2017-07-14 16:53:18 Functions: 23 30 76.7 %
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             : #ifndef nsTimerImpl_h___
       8             : #define nsTimerImpl_h___
       9             : 
      10             : #include "nsITimer.h"
      11             : #include "nsIEventTarget.h"
      12             : #include "nsIObserver.h"
      13             : 
      14             : #include "nsCOMPtr.h"
      15             : 
      16             : #include "mozilla/Attributes.h"
      17             : #include "mozilla/Logging.h"
      18             : #include "mozilla/Mutex.h"
      19             : #include "mozilla/TimeStamp.h"
      20             : #include "mozilla/Variant.h"
      21             : 
      22             : #ifdef MOZ_TASK_TRACER
      23             : #include "TracedTaskCommon.h"
      24             : #endif
      25             : 
      26             : extern mozilla::LogModule* GetTimerLog();
      27             : 
      28             : #define NS_TIMER_CID \
      29             : { /* 5ff24248-1dd2-11b2-8427-fbab44f29bc8 */         \
      30             :      0x5ff24248,                                     \
      31             :      0x1dd2,                                         \
      32             :      0x11b2,                                         \
      33             :     {0x84, 0x27, 0xfb, 0xab, 0x44, 0xf2, 0x9b, 0xc8} \
      34             : }
      35             : 
      36             : class nsTimerImplHolder;
      37             : 
      38             : // TimerThread, nsTimerEvent, and nsTimer have references to these. nsTimer has
      39             : // a separate lifecycle so we can Cancel() the underlying timer when the user of
      40             : // the nsTimer has let go of its last reference.
      41             : class nsTimerImpl
      42             : {
      43          83 :   ~nsTimerImpl()
      44          83 :   {
      45          83 :     MOZ_ASSERT(!mHolder);
      46          83 :   }
      47             : 
      48             : public:
      49             :   typedef mozilla::TimeStamp TimeStamp;
      50             : 
      51             :   explicit nsTimerImpl(nsITimer* aTimer);
      52         942 :   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(nsTimerImpl)
      53             :   NS_DECL_NON_VIRTUAL_NSITIMER
      54             : 
      55             :   static nsresult Startup();
      56             :   static void Shutdown();
      57             : 
      58             :   void SetDelayInternal(uint32_t aDelay, TimeStamp aBase = TimeStamp::Now());
      59             :   bool CancelCheckIfFiring();
      60             : 
      61             :   void Fire(int32_t aGeneration);
      62             : 
      63             : #ifdef MOZ_TASK_TRACER
      64             :   void GetTLSTraceInfo();
      65             :   mozilla::tasktracer::TracedTaskCommon GetTracedTask();
      66             : #endif
      67             : 
      68          90 :   int32_t GetGeneration()
      69             :   {
      70          90 :     return mGeneration;
      71             :   }
      72             : 
      73             :   struct Callback {
      74        2222 :     Callback() :
      75             :       mType(Type::Unknown),
      76             :       mName(Nothing),
      77        2222 :       mClosure(nullptr)
      78             :     {
      79        2222 :       mCallback.c = nullptr;
      80        2222 :     }
      81             : 
      82             :     Callback(const Callback& other) = delete;
      83             :     Callback& operator=(const Callback& other) = delete;
      84             : 
      85        1953 :     ~Callback()
      86        1953 :     {
      87        1953 :       if (mType == Type::Interface) {
      88          60 :         NS_RELEASE(mCallback.i);
      89        1893 :       } else if (mType == Type::Observer) {
      90           6 :         NS_RELEASE(mCallback.o);
      91             :       }
      92        1953 :     }
      93             : 
      94        1878 :     void swap(Callback& other)
      95             :     {
      96        1878 :       std::swap(mType, other.mType);
      97        1878 :       std::swap(mCallback, other.mCallback);
      98        1878 :       std::swap(mName, other.mName);
      99        1878 :       std::swap(mClosure, other.mClosure);
     100        1878 :     }
     101             : 
     102             :     enum class Type : uint8_t {
     103             :       Unknown = 0,
     104             :       Interface = 1,
     105             :       Function = 2,
     106             :       Observer = 3,
     107             :     };
     108             :     Type mType;
     109             : 
     110             :     union CallbackUnion
     111             :     {
     112             :       nsTimerCallbackFunc c;
     113             :       // These refcounted references are managed manually, as they are in a union
     114             :       nsITimerCallback* MOZ_OWNING_REF i;
     115             :       nsIObserver* MOZ_OWNING_REF o;
     116             :     } mCallback;
     117             : 
     118             :     // |Name| is a tagged union type representing one of (a) nothing, (b) a
     119             :     // string, or (c) a function. mozilla::Variant doesn't naturally handle the
     120             :     // "nothing" case, so we define a dummy type and value (which is unused and
     121             :     // so the exact value doesn't matter) for it.
     122             :     typedef const int NameNothing;
     123             :     typedef const char* NameString;
     124             :     typedef nsTimerNameCallbackFunc NameFunc;
     125             :     typedef mozilla::Variant<NameNothing, NameString, NameFunc> Name;
     126             :     static const NameNothing Nothing;
     127             :     Name mName;
     128             : 
     129             :     void*                 mClosure;
     130             :   };
     131             : 
     132             :   nsresult InitCommon(uint32_t aDelayMS, uint32_t aType,
     133             :                       Callback&& newCallback);
     134             : 
     135             :   nsresult InitCommon(const TimeDuration& aDelay, uint32_t aType,
     136             :                       Callback&& newCallback);
     137             : 
     138          85 :   Callback& GetCallback()
     139             :   {
     140          85 :     mMutex.AssertCurrentThreadOwns();
     141          85 :     if (mCallback.mType == Callback::Type::Unknown) {
     142           5 :       return mCallbackDuringFire;
     143             :     }
     144             : 
     145          80 :     return mCallback;
     146             :   }
     147             : 
     148          37 :   bool IsRepeating() const
     149             :   {
     150             :     static_assert(nsITimer::TYPE_ONE_SHOT < nsITimer::TYPE_REPEATING_SLACK,
     151             :                   "invalid ordering of timer types!");
     152             :     static_assert(
     153             :         nsITimer::TYPE_REPEATING_SLACK < nsITimer::TYPE_REPEATING_PRECISE,
     154             :         "invalid ordering of timer types!");
     155             :     static_assert(
     156             :         nsITimer::TYPE_REPEATING_PRECISE <
     157             :           nsITimer::TYPE_REPEATING_PRECISE_CAN_SKIP,
     158             :         "invalid ordering of timer types!");
     159          60 :     return mType >= nsITimer::TYPE_REPEATING_SLACK &&
     160          60 :            mType < nsITimer::TYPE_ONE_SHOT_LOW_PRIORITY;
     161             :   }
     162             : 
     163           6 :   bool IsLowPriority() const
     164             :   {
     165          12 :     return mType == nsITimer::TYPE_ONE_SHOT_LOW_PRIORITY ||
     166          12 :            mType == nsITimer::TYPE_REPEATING_SLACK_LOW_PRIORITY;
     167             :   }
     168             : 
     169          18 :   bool IsSlack() const
     170             :   {
     171          36 :     return mType == nsITimer::TYPE_REPEATING_SLACK ||
     172          36 :            mType == nsITimer::TYPE_REPEATING_SLACK_LOW_PRIORITY;
     173             :   }
     174             : 
     175             :   void GetName(nsACString& aName);
     176             : 
     177             :   void SetHolder(nsTimerImplHolder* aHolder);
     178             : 
     179             :   nsCOMPtr<nsIEventTarget> mEventTarget;
     180             : 
     181             :   void LogFiring(const Callback& aCallback, uint8_t aType, uint32_t aDelay);
     182             : 
     183             :   nsresult InitWithFuncCallbackCommon(nsTimerCallbackFunc aFunc,
     184             :                                       void* aClosure,
     185             :                                       uint32_t aDelay,
     186             :                                       uint32_t aType,
     187             :                                       const Callback::Name& aName);
     188             : 
     189             :   // This weak reference must be cleared by the nsTimerImplHolder by calling
     190             :   // SetHolder(nullptr) before the holder is destroyed.
     191             :   nsTimerImplHolder*    mHolder;
     192             : 
     193             :   // These members are set by the initiating thread, when the timer's type is
     194             :   // changed and during the period where it fires on that thread.
     195             :   uint8_t               mType;
     196             : 
     197             :   // The generation number of this timer, re-generated each time the timer is
     198             :   // initialized so one-shot timers can be canceled and re-initialized by the
     199             :   // arming thread without any bad race conditions.
     200             :   // Updated only after this timer has been removed from the timer thread.
     201             :   int32_t               mGeneration;
     202             : 
     203             :   TimeDuration          mDelay;
     204             :   // Updated only after this timer has been removed from the timer thread.
     205             :   TimeStamp             mTimeout;
     206             : 
     207             : #ifdef MOZ_TASK_TRACER
     208             :   mozilla::tasktracer::TracedTaskCommon mTracedTask;
     209             : #endif
     210             : 
     211             :   static double         sDeltaSum;
     212             :   static double         sDeltaSumSquared;
     213             :   static double         sDeltaNum;
     214             :   const RefPtr<nsITimer>      mITimer;
     215             :   mozilla::Mutex mMutex;
     216             :   Callback              mCallback;
     217             :   Callback              mCallbackDuringFire;
     218             : };
     219             : 
     220             : class nsTimer final : public nsITimer
     221             : {
     222             :   virtual ~nsTimer();
     223             : public:
     224         436 :   nsTimer() : mImpl(new nsTimerImpl(this)) {}
     225             : 
     226             :   friend class TimerThread;
     227             :   friend class nsTimerEvent;
     228             :   friend struct TimerAdditionComparator;
     229             : 
     230             :   NS_DECL_THREADSAFE_ISUPPORTS
     231        1830 :   NS_FORWARD_SAFE_NSITIMER(mImpl);
     232             : 
     233             :   virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
     234             : 
     235             : private:
     236             :   // nsTimerImpl holds a strong ref to us. When our refcount goes to 1, we will
     237             :   // null this to break the cycle.
     238             :   RefPtr<nsTimerImpl> mImpl;
     239             : };
     240             : 
     241             : // A class that holds on to an nsTimerImpl.  This lets the nsTimerImpl object
     242             : // directly instruct its holder to forget the timer, avoiding list lookups.
     243             : class nsTimerImplHolder
     244             : {
     245             : public:
     246         306 :   explicit nsTimerImplHolder(nsTimerImpl* aTimerImpl)
     247         306 :     : mTimerImpl(aTimerImpl)
     248             :   {
     249         306 :     if (mTimerImpl) {
     250         306 :       mTimerImpl->SetHolder(this);
     251             :     }
     252         306 :   }
     253             : 
     254         180 :   ~nsTimerImplHolder()
     255         180 :   {
     256         180 :     if (mTimerImpl) {
     257           0 :       mTimerImpl->SetHolder(nullptr);
     258             :     }
     259         180 :   }
     260             : 
     261             :   void
     262         174 :   Forget(nsTimerImpl* aTimerImpl)
     263             :   {
     264         174 :     if (MOZ_UNLIKELY(!mTimerImpl)) {
     265           0 :       return;
     266             :     }
     267         174 :     MOZ_ASSERT(aTimerImpl == mTimerImpl);
     268         174 :     mTimerImpl->SetHolder(nullptr);
     269         174 :     mTimerImpl = nullptr;
     270             :   }
     271             : 
     272             : protected:
     273             :   RefPtr<nsTimerImpl> mTimerImpl;
     274             : };
     275             : 
     276             : 
     277             : #endif /* nsTimerImpl_h___ */

Generated by: LCOV version 1.13