LCOV - code coverage report
Current view: top level - xpcom/threads - nsThreadUtils.h (source / functions) Hit Total Coverage
Test: output.info Lines: 135 150 90.0 %
Date: 2017-07-14 16:53:18 Functions: 1176 8443 13.9 %
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 nsThreadUtils_h__
       8             : #define nsThreadUtils_h__
       9             : 
      10             : #include "prthread.h"
      11             : #include "prinrval.h"
      12             : #include "MainThreadUtils.h"
      13             : #include "nsICancelableRunnable.h"
      14             : #include "nsIIdlePeriod.h"
      15             : #include "nsIIdleRunnable.h"
      16             : #include "nsINamed.h"
      17             : #include "nsIRunnable.h"
      18             : #include "nsIThreadManager.h"
      19             : #include "nsITimer.h"
      20             : #include "nsIThread.h"
      21             : #include "nsStringGlue.h"
      22             : #include "nsCOMPtr.h"
      23             : #include "nsAutoPtr.h"
      24             : #include "mozilla/Atomics.h"
      25             : #include "mozilla/IndexSequence.h"
      26             : #include "mozilla/Likely.h"
      27             : #include "mozilla/Move.h"
      28             : #include "mozilla/TimeStamp.h"
      29             : #include "mozilla/Tuple.h"
      30             : #include "mozilla/TypeTraits.h"
      31             : 
      32             : //-----------------------------------------------------------------------------
      33             : // These methods are alternatives to the methods on nsIThreadManager, provided
      34             : // for convenience.
      35             : 
      36             : /**
      37             :  * Create a new thread, and optionally provide an initial event for the thread.
      38             :  *
      39             :  * @param aResult
      40             :  *   The resulting nsIThread object.
      41             :  * @param aInitialEvent
      42             :  *   The initial event to run on this thread.  This parameter may be null.
      43             :  * @param aStackSize
      44             :  *   The size in bytes to reserve for the thread's stack.
      45             :  *
      46             :  * @returns NS_ERROR_INVALID_ARG
      47             :  *   Indicates that the given name is not unique.
      48             :  */
      49             : extern nsresult
      50             : NS_NewThread(nsIThread** aResult,
      51             :              nsIRunnable* aInitialEvent = nullptr,
      52             :              uint32_t aStackSize = nsIThreadManager::DEFAULT_STACK_SIZE);
      53             : 
      54             : /**
      55             :  * Creates a named thread, otherwise the same as NS_NewThread
      56             :  */
      57             : extern nsresult
      58             : NS_NewNamedThread(const nsACString& aName,
      59             :                   nsIThread** aResult,
      60             :                   nsIRunnable* aInitialEvent = nullptr,
      61             :                   uint32_t aStackSize = nsIThreadManager::DEFAULT_STACK_SIZE);
      62             : 
      63             : template<size_t LEN>
      64             : inline nsresult
      65          29 : NS_NewNamedThread(const char (&aName)[LEN],
      66             :                   nsIThread** aResult,
      67             :                   nsIRunnable* aInitialEvent = nullptr,
      68             :                   uint32_t aStackSize = nsIThreadManager::DEFAULT_STACK_SIZE)
      69             : {
      70             :   static_assert(LEN <= 16,
      71             :                 "Thread name must be no more than 16 characters");
      72          58 :   return NS_NewNamedThread(nsDependentCString(aName, LEN - 1),
      73          58 :                            aResult, aInitialEvent, aStackSize);
      74             : }
      75             : 
      76             : /**
      77             :  * Get a reference to the current thread.
      78             :  *
      79             :  * @param aResult
      80             :  *   The resulting nsIThread object.
      81             :  */
      82             : extern nsresult NS_GetCurrentThread(nsIThread** aResult);
      83             : 
      84             : /**
      85             :  * Dispatch the given event to the current thread.
      86             :  *
      87             :  * @param aEvent
      88             :  *   The event to dispatch.
      89             :  *
      90             :  * @returns NS_ERROR_INVALID_ARG
      91             :  *   If event is null.
      92             :  */
      93             : extern nsresult NS_DispatchToCurrentThread(nsIRunnable* aEvent);
      94             : extern nsresult
      95             : NS_DispatchToCurrentThread(already_AddRefed<nsIRunnable>&& aEvent);
      96             : 
      97             : /**
      98             :  * Dispatch the given event to the main thread.
      99             :  *
     100             :  * @param aEvent
     101             :  *   The event to dispatch.
     102             :  * @param aDispatchFlags
     103             :  *   The flags to pass to the main thread's dispatch method.
     104             :  *
     105             :  * @returns NS_ERROR_INVALID_ARG
     106             :  *   If event is null.
     107             :  */
     108             : extern nsresult
     109             : NS_DispatchToMainThread(nsIRunnable* aEvent,
     110             :                         uint32_t aDispatchFlags = NS_DISPATCH_NORMAL);
     111             : extern nsresult
     112             : NS_DispatchToMainThread(already_AddRefed<nsIRunnable>&& aEvent,
     113             :                         uint32_t aDispatchFlags = NS_DISPATCH_NORMAL);
     114             : 
     115             : extern nsresult
     116             : NS_DelayedDispatchToCurrentThread(
     117             :   already_AddRefed<nsIRunnable>&& aEvent, uint32_t aDelayMs);
     118             : 
     119             : /**
     120             :  * Dispatch the given event to the idle queue of the current thread.
     121             :  *
     122             :  * @param aEvent
     123             :  *   The event to dispatch.
     124             :   *
     125             :  * @returns NS_ERROR_INVALID_ARG
     126             :  *   If event is null.
     127             :  * @returns NS_ERROR_UNEXPECTED
     128             :  *   If the thread is shutting down.
     129             :  */
     130             : extern nsresult
     131             : NS_IdleDispatchToCurrentThread(already_AddRefed<nsIRunnable>&& aEvent);
     132             : 
     133             : /**
     134             :  * Dispatch the given event to the idle queue of the current thread.
     135             :  *
     136             :  * @param aEvent The event to dispatch. If the event implements
     137             :  *   nsIIdleRunnable, it will receive a call on
     138             :  *   nsIIdleRunnable::SetTimer when dispatched, with the value of
     139             :  *   aTimeout.
     140             :  *
     141             :  * @param aTimeout The time in milliseconds until the event should be
     142             :  *   moved from the idle queue to the regular queue, if it hasn't been
     143             :  *   executed. If aEvent is also an nsIIdleRunnable, it is expected
     144             :  *   that it should handle the timeout itself, after a call to
     145             :  *   nsIIdleRunnable::SetTimer.
     146             :  *
     147             :  * @returns NS_ERROR_INVALID_ARG
     148             :  *   If event is null.
     149             :  * @returns NS_ERROR_UNEXPECTED
     150             :  *   If the thread is shutting down.
     151             :  */
     152             : extern nsresult
     153             : NS_IdleDispatchToCurrentThread(already_AddRefed<nsIRunnable>&& aEvent, uint32_t aTimeout);
     154             : 
     155             : /**
     156             :  * Dispatch the given event to the idle queue of a thread.
     157             :  *
     158             :  * @param aEvent The event to dispatch.
     159             :  *
     160             :  * @param aThread The target thread for the dispatch.
     161             :  *
     162             :  * @returns NS_ERROR_INVALID_ARG
     163             :  *   If event is null.
     164             :  * @returns NS_ERROR_UNEXPECTED
     165             :  *   If the thread is shutting down.
     166             :  */
     167             : extern nsresult
     168             : NS_IdleDispatchToThread(already_AddRefed<nsIRunnable>&& aEvent,
     169             :                         nsIThread* aThread);
     170             : 
     171             : /**
     172             :  * Dispatch the given event to the idle queue of a thread.
     173             :  *
     174             :  * @param aEvent The event to dispatch. If the event implements
     175             :  *   nsIIdleRunnable, it will receive a call on
     176             :  *   nsIIdleRunnable::SetTimer when dispatched, with the value of
     177             :  *   aTimeout.
     178             :  *
     179             :  * @param aTimeout The time in milliseconds until the event should be
     180             :  *   moved from the idle queue to the regular queue, if it hasn't been
     181             :  *   executed. If aEvent is also an nsIIdleRunnable, it is expected
     182             :  *   that it should handle the timeout itself, after a call to
     183             :  *   nsIIdleRunnable::SetTimer.
     184             :  *
     185             :  * @param aThread The target thread for the dispatch.
     186             :  *
     187             :  * @returns NS_ERROR_INVALID_ARG
     188             :  *   If event is null.
     189             :  * @returns NS_ERROR_UNEXPECTED
     190             :  *   If the thread is shutting down.
     191             :  */
     192             : extern nsresult
     193             : NS_IdleDispatchToThread(already_AddRefed<nsIRunnable>&& aEvent,
     194             :                         uint32_t aTimeout,
     195             :                         nsIThread* aThread);
     196             : 
     197             : #ifndef XPCOM_GLUE_AVOID_NSPR
     198             : /**
     199             :  * Process all pending events for the given thread before returning.  This
     200             :  * method simply calls ProcessNextEvent on the thread while HasPendingEvents
     201             :  * continues to return true and the time spent in NS_ProcessPendingEvents
     202             :  * does not exceed the given timeout value.
     203             :  *
     204             :  * @param aThread
     205             :  *   The thread object for which to process pending events.  If null, then
     206             :  *   events will be processed for the current thread.
     207             :  * @param aTimeout
     208             :  *   The maximum number of milliseconds to spend processing pending events.
     209             :  *   Events are not pre-empted to honor this timeout.  Rather, the timeout
     210             :  *   value is simply used to determine whether or not to process another event.
     211             :  *   Pass PR_INTERVAL_NO_TIMEOUT to specify no timeout.
     212             :  */
     213             : extern nsresult
     214             : NS_ProcessPendingEvents(nsIThread* aThread,
     215             :                         PRIntervalTime aTimeout = PR_INTERVAL_NO_TIMEOUT);
     216             : #endif
     217             : 
     218             : /**
     219             :  * Shortcut for nsIThread::HasPendingEvents.
     220             :  *
     221             :  * It is an error to call this function when the given thread is not the
     222             :  * current thread.  This function will return false if called from some
     223             :  * other thread.
     224             :  *
     225             :  * @param aThread
     226             :  *   The current thread or null.
     227             :  *
     228             :  * @returns
     229             :  *   A boolean value that if "true" indicates that there are pending events
     230             :  *   in the current thread's event queue.
     231             :  */
     232             : extern bool NS_HasPendingEvents(nsIThread* aThread = nullptr);
     233             : 
     234             : /**
     235             :  * Shortcut for nsIThread::ProcessNextEvent.
     236             :  *
     237             :  * It is an error to call this function when the given thread is not the
     238             :  * current thread.  This function will simply return false if called
     239             :  * from some other thread.
     240             :  *
     241             :  * @param aThread
     242             :  *   The current thread or null.
     243             :  * @param aMayWait
     244             :  *   A boolean parameter that if "true" indicates that the method may block
     245             :  *   the calling thread to wait for a pending event.
     246             :  *
     247             :  * @returns
     248             :  *   A boolean value that if "true" indicates that an event from the current
     249             :  *   thread's event queue was processed.
     250             :  */
     251             : extern bool NS_ProcessNextEvent(nsIThread* aThread = nullptr,
     252             :                                 bool aMayWait = true);
     253             : 
     254             : // A wrapper for nested event loops.
     255             : //
     256             : // This function is intended to make code more obvious (do you remember
     257             : // what NS_ProcessNextEvent(nullptr, true) means?) and slightly more
     258             : // efficient, as people often pass nullptr or NS_GetCurrentThread to
     259             : // NS_ProcessNextEvent, which results in needless querying of the current
     260             : // thread every time through the loop.
     261             : //
     262             : // You should use this function in preference to NS_ProcessNextEvent inside
     263             : // a loop unless one of the following is true:
     264             : //
     265             : // * You need to pass `false` to NS_ProcessNextEvent; or
     266             : // * You need to do unusual things around the call to NS_ProcessNextEvent,
     267             : //   such as unlocking mutexes that you are holding.
     268             : //
     269             : // If you *do* need to call NS_ProcessNextEvent manually, please do call
     270             : // NS_GetCurrentThread() outside of your loop and pass the returned pointer
     271             : // into NS_ProcessNextEvent for a tiny efficiency win.
     272             : namespace mozilla {
     273             : 
     274             : // You should normally not need to deal with this template parameter.  If
     275             : // you enjoy esoteric event loop details, read on.
     276             : //
     277             : // If you specify that NS_ProcessNextEvent wait for an event, it is possible
     278             : // for NS_ProcessNextEvent to return false, i.e. to indicate that an event
     279             : // was not processed.  This can only happen when the thread has been shut
     280             : // down by another thread, but is still attempting to process events outside
     281             : // of a nested event loop.
     282             : //
     283             : // This behavior is admittedly strange.  The scenario it deals with is the
     284             : // following:
     285             : //
     286             : // * The current thread has been shut down by some owner thread.
     287             : // * The current thread is spinning an event loop waiting for some condition
     288             : //   to become true.
     289             : // * Said condition is actually being fulfilled by another thread, so there
     290             : //   are timing issues in play.
     291             : //
     292             : // Thus, there is a small window where the current thread's event loop
     293             : // spinning can check the condition, find it false, and call
     294             : // NS_ProcessNextEvent to wait for another event.  But we don't actually
     295             : // want it to wait indefinitely, because there might not be any other events
     296             : // in the event loop, and the current thread can't accept dispatched events
     297             : // because it's being shut down.  Thus, actually blocking would hang the
     298             : // thread, which is bad.  The solution, then, is to detect such a scenario
     299             : // and not actually block inside NS_ProcessNextEvent.
     300             : //
     301             : // But this is a problem, because we want to return the status of
     302             : // NS_ProcessNextEvent to the caller of SpinEventLoopUntil if possible.  In
     303             : // the above scenario, however, we'd stop spinning prematurely and cause
     304             : // all sorts of havoc.  We therefore have this template parameter to
     305             : // control whether errors are ignored or passed out to the caller of
     306             : // SpinEventLoopUntil.  The latter is the default; if you find yourself
     307             : // wanting to use the former, you should think long and hard before doing
     308             : // so, and write a comment like this defending your choice.
     309             : 
     310             : enum class ProcessFailureBehavior {
     311             :   IgnoreAndContinue,
     312             :   ReportToCaller,
     313             : };
     314             : 
     315             : template<ProcessFailureBehavior Behavior = ProcessFailureBehavior::ReportToCaller,
     316             :          typename Pred>
     317             : bool
     318           3 : SpinEventLoopUntil(Pred&& aPredicate, nsIThread* aThread = nullptr)
     319             : {
     320           3 :   nsIThread* thread = aThread ? aThread : NS_GetCurrentThread();
     321             : 
     322          37 :   while (!aPredicate()) {
     323          17 :     bool didSomething = NS_ProcessNextEvent(thread, true);
     324             : 
     325             :     if (Behavior == ProcessFailureBehavior::IgnoreAndContinue) {
     326             :       // Don't care what happened, continue on.
     327           0 :       continue;
     328          17 :     } else if (!didSomething) {
     329           0 :       return false;
     330             :     }
     331             :   }
     332             : 
     333           3 :   return true;
     334             : }
     335             : 
     336             : } // namespace mozilla
     337             : 
     338             : /**
     339             :  * Returns true if we're in the compositor thread.
     340             :  *
     341             :  * We declare this here because the headers required to invoke
     342             :  * CompositorThreadHolder::IsInCompositorThread() also pull in a bunch of system
     343             :  * headers that #define various tokens in a way that can break the build.
     344             :  */
     345             : extern bool NS_IsInCompositorThread();
     346             : 
     347             : //-----------------------------------------------------------------------------
     348             : // Helpers that work with nsCOMPtr:
     349             : 
     350             : inline already_AddRefed<nsIThread>
     351          23 : do_GetCurrentThread()
     352             : {
     353          23 :   nsIThread* thread = nullptr;
     354          23 :   NS_GetCurrentThread(&thread);
     355          23 :   return already_AddRefed<nsIThread>(thread);
     356             : }
     357             : 
     358             : inline already_AddRefed<nsIThread>
     359         298 : do_GetMainThread()
     360             : {
     361         298 :   nsIThread* thread = nullptr;
     362         298 :   NS_GetMainThread(&thread);
     363         298 :   return already_AddRefed<nsIThread>(thread);
     364             : }
     365             : 
     366             : //-----------------------------------------------------------------------------
     367             : 
     368             : #ifdef MOZILLA_INTERNAL_API
     369             : // Fast access to the current thread.  Do not release the returned pointer!  If
     370             : // you want to use this pointer from some other thread, then you will need to
     371             : // AddRef it.  Otherwise, you should only consider this pointer valid from code
     372             : // running on the current thread.
     373             : extern nsIThread* NS_GetCurrentThread();
     374             : 
     375             : /**
     376             :  * Set the name of the current thread. Prefer this function over
     377             :  * PR_SetCurrentThreadName() if possible. The name will also be included in the
     378             :  * crash report.
     379             :  *
     380             :  * @param aName
     381             :  *   Name of the thread. A C language null-terminated string.
     382             :  */
     383             : extern void NS_SetCurrentThreadName(const char* aName);
     384             : #endif
     385             : 
     386             : //-----------------------------------------------------------------------------
     387             : 
     388             : #ifndef XPCOM_GLUE_AVOID_NSPR
     389             : 
     390             : namespace mozilla {
     391             : 
     392             : // This class is designed to be subclassed.
     393             : class IdlePeriod : public nsIIdlePeriod
     394             : {
     395             : public:
     396             :   NS_DECL_THREADSAFE_ISUPPORTS
     397             :   NS_DECL_NSIIDLEPERIOD
     398             : 
     399          69 :   IdlePeriod() {}
     400             : 
     401             : protected:
     402          12 :   virtual ~IdlePeriod() {}
     403             : private:
     404             :   IdlePeriod(const IdlePeriod&) = delete;
     405             :   IdlePeriod& operator=(const IdlePeriod&) = delete;
     406             :   IdlePeriod& operator=(const IdlePeriod&&) = delete;
     407             : };
     408             : 
     409             : // Cancelable runnable methods implement nsICancelableRunnable, and
     410             : // Idle and IdleWithTimer also nsIIdleRunnable.
     411             : enum RunnableKind
     412             : {
     413             :   Standard,
     414             :   Cancelable,
     415             :   Idle,
     416             :   IdleWithTimer
     417             : };
     418             : 
     419             : // This class is designed to be subclassed.
     420             : class Runnable : public nsIRunnable, public nsINamed
     421             : {
     422             : public:
     423             :   NS_DECL_THREADSAFE_ISUPPORTS
     424             :   NS_DECL_NSIRUNNABLE
     425             :   NS_DECL_NSINAMED
     426             : 
     427             :   Runnable() = delete;
     428             : 
     429             : #ifdef RELEASE_OR_BETA
     430             :   explicit Runnable(const char* aName) {}
     431             : #else
     432        3797 :   explicit Runnable(const char* aName) : mName(aName) {}
     433             : #endif
     434             : 
     435             : protected:
     436        3590 :   virtual ~Runnable() {}
     437             : 
     438             : #ifndef RELEASE_OR_BETA
     439             :   const char* mName = nullptr;
     440             : #endif
     441             : 
     442             : private:
     443             :   Runnable(const Runnable&) = delete;
     444             :   Runnable& operator=(const Runnable&) = delete;
     445             :   Runnable& operator=(const Runnable&&) = delete;
     446             : };
     447             : 
     448             : // This class is designed to be subclassed.
     449             : class CancelableRunnable : public Runnable,
     450             :                            public nsICancelableRunnable
     451             : {
     452             : public:
     453             :   NS_DECL_ISUPPORTS_INHERITED
     454             :   // nsICancelableRunnable
     455             :   virtual nsresult Cancel() override;
     456             : 
     457             :   CancelableRunnable() = delete;
     458        1652 :   explicit CancelableRunnable(const char* aName) : Runnable(aName) {}
     459             : 
     460             : protected:
     461        1516 :   virtual ~CancelableRunnable() {}
     462             : private:
     463             :   CancelableRunnable(const CancelableRunnable&) = delete;
     464             :   CancelableRunnable& operator=(const CancelableRunnable&) = delete;
     465             :   CancelableRunnable& operator=(const CancelableRunnable&&) = delete;
     466             : };
     467             : 
     468             : // This class is designed to be subclassed.
     469             : class IdleRunnable : public CancelableRunnable,
     470             :                      public nsIIdleRunnable
     471             : {
     472             : public:
     473             :   NS_DECL_ISUPPORTS_INHERITED
     474             : 
     475          10 :   IdleRunnable()
     476          10 :     : CancelableRunnable("IdleRunnable")
     477             :   {
     478          10 :   }
     479             :   explicit IdleRunnable(const char* aName) : CancelableRunnable(aName) {}
     480             : 
     481             : protected:
     482           4 :   virtual ~IdleRunnable() {}
     483             : private:
     484             :   IdleRunnable(const IdleRunnable&) = delete;
     485             :   IdleRunnable& operator=(const IdleRunnable&) = delete;
     486             :   IdleRunnable& operator=(const IdleRunnable&&) = delete;
     487             : };
     488             : 
     489             : namespace detail {
     490             : 
     491             : // An event that can be used to call a C++11 functions or function objects,
     492             : // including lambdas. The function must have no required arguments, and must
     493             : // return void.
     494             : template<typename StoredFunction>
     495         324 : class RunnableFunction : public Runnable
     496             : {
     497             : public:
     498             :   template <typename F>
     499         108 :   explicit RunnableFunction(F&& aFunction)
     500             :     : Runnable("RunnableFunction")
     501         108 :     , mFunction(Forward<F>(aFunction))
     502         108 :   { }
     503             : 
     504         108 :   NS_IMETHOD Run() override {
     505             :     static_assert(IsVoid<decltype(mFunction())>::value,
     506             :                   "The lambda must return void!");
     507         108 :     mFunction();
     508         108 :     return NS_OK;
     509             :   }
     510             : private:
     511             :   StoredFunction mFunction;
     512             : };
     513             : 
     514             : // Type alias for NS_NewRunnableFunction
     515             : template<typename Function>
     516             : using RunnableFunctionImpl =
     517             :   // Make sure we store a non-reference in nsRunnableFunction.
     518             :   typename detail::RunnableFunction<typename RemoveReference<Function>::Type>;
     519             : 
     520             : template <typename T>
     521             : inline already_AddRefed<T>
     522        1643 : SetRunnableName(const char* aName, T* aObj)
     523             : {
     524             : #ifdef RELEASE_OR_BETA
     525             :   return do_AddRef(aObj);
     526             : #else
     527        1643 :   MOZ_RELEASE_ASSERT(aName);
     528        3286 :   RefPtr<T> ref(aObj);
     529        1643 :   ref->SetName(aName);
     530        3286 :   return ref.forget();
     531             : #endif
     532             : }
     533             : 
     534             : } // namespace detail
     535             : 
     536             : namespace detail {
     537             : 
     538             : template<typename CVRemoved>
     539             : struct IsRefcountedSmartPointerHelper : FalseType {};
     540             : 
     541             : template<typename Pointee>
     542             : struct IsRefcountedSmartPointerHelper<RefPtr<Pointee>> : TrueType {};
     543             : 
     544             : template<typename Pointee>
     545             : struct IsRefcountedSmartPointerHelper<nsCOMPtr<Pointee>> : TrueType {};
     546             : 
     547             : } // namespace detail
     548             : 
     549             : template<typename T>
     550             : struct IsRefcountedSmartPointer
     551             :   : detail::IsRefcountedSmartPointerHelper<typename RemoveCV<T>::Type>
     552             : {};
     553             : 
     554             : namespace detail {
     555             : 
     556             : template<typename T, typename CVRemoved>
     557             : struct RemoveSmartPointerHelper
     558             : {
     559             :   typedef T Type;
     560             : };
     561             : 
     562             : template<typename T, typename Pointee>
     563             : struct RemoveSmartPointerHelper<T, RefPtr<Pointee>>
     564             : {
     565             :   typedef Pointee Type;
     566             : };
     567             : 
     568             : template<typename T, typename Pointee>
     569             : struct RemoveSmartPointerHelper<T, nsCOMPtr<Pointee>>
     570             : {
     571             :   typedef Pointee Type;
     572             : };
     573             : 
     574             : } // namespace detail
     575             : 
     576             : template<typename T>
     577             : struct RemoveSmartPointer
     578             :   : detail::RemoveSmartPointerHelper<T, typename RemoveCV<T>::Type>
     579             : {};
     580             : 
     581             : namespace detail {
     582             : 
     583             : template<typename T, typename CVRemoved>
     584             : struct RemoveRawOrSmartPointerHelper
     585             : {
     586             :   typedef T Type;
     587             : };
     588             : 
     589             : template<typename T, typename Pointee>
     590             : struct RemoveRawOrSmartPointerHelper<T, Pointee*>
     591             : {
     592             :   typedef Pointee Type;
     593             : };
     594             : 
     595             : template<typename T, typename Pointee>
     596             : struct RemoveRawOrSmartPointerHelper<T, RefPtr<Pointee>>
     597             : {
     598             :   typedef Pointee Type;
     599             : };
     600             : 
     601             : template<typename T, typename Pointee>
     602             : struct RemoveRawOrSmartPointerHelper<T, nsCOMPtr<Pointee>>
     603             : {
     604             :   typedef Pointee Type;
     605             : };
     606             : 
     607             : } // namespace detail
     608             : 
     609             : template<typename T>
     610             : struct RemoveRawOrSmartPointer
     611             :   : detail::RemoveRawOrSmartPointerHelper<T, typename RemoveCV<T>::Type>
     612             : {};
     613             : 
     614             : } // namespace mozilla
     615             : 
     616             : inline nsISupports*
     617           0 : ToSupports(mozilla::Runnable *p)
     618             : {
     619           0 :   return static_cast<nsIRunnable*>(p);
     620             : }
     621             : 
     622             : template<typename Function>
     623             : already_AddRefed<mozilla::Runnable>
     624         108 : NS_NewRunnableFunction(const char* aName, Function&& aFunction)
     625             : {
     626             :   // We store a non-reference in RunnableFunction, but still forward aFunction
     627             :   // to move if possible.
     628             :   return mozilla::detail::SetRunnableName(
     629             :     aName,
     630         108 :     new mozilla::detail::RunnableFunctionImpl<Function>(
     631         216 :       mozilla::Forward<Function>(aFunction)));
     632             : }
     633             : 
     634             : namespace mozilla {
     635             : namespace detail {
     636             : 
     637             : already_AddRefed<nsITimer> CreateTimer();
     638             : 
     639             : template <RunnableKind Kind>
     640        1554 : class TimerBehaviour
     641             : {
     642             : public:
     643             :   nsITimer* GetTimer() { return nullptr; }
     644        3062 :   void CancelTimer() {}
     645             : 
     646             : protected:
     647        1482 :   ~TimerBehaviour() {}
     648             : };
     649             : 
     650             : template <>
     651             : class TimerBehaviour<IdleWithTimer>
     652             : {
     653             : public:
     654             :   nsITimer* GetTimer()
     655             :   {
     656             :     if (!mTimer) {
     657             :       mTimer = CreateTimer();
     658             :     }
     659             : 
     660             :     return mTimer;
     661             :   }
     662             : 
     663             :   void CancelTimer()
     664             :   {
     665             :     if (mTimer) {
     666             :       mTimer->Cancel();
     667             :     }
     668             :   }
     669             : 
     670             : protected:
     671             :   ~TimerBehaviour()
     672             :   {
     673             :     CancelTimer();
     674             :   }
     675             : private:
     676             :   nsCOMPtr<nsITimer> mTimer;
     677             : };
     678             : 
     679             : } // namespace detail
     680             : } // namespace mozilla
     681             : 
     682             : // An event that can be used to call a method on a class.  The class type must
     683             : // support reference counting. This event supports Revoke for use
     684             : // with nsRevocableEventPtr.
     685             : template<class ClassType,
     686             :          typename ReturnType = void,
     687             :          bool Owning = true,
     688             :          mozilla::RunnableKind Kind = mozilla::Standard>
     689        1464 : class nsRunnableMethod
     690             :   : public mozilla::Conditional<Kind == mozilla::Standard,
     691             :                                 mozilla::Runnable,
     692             :                                 typename mozilla::Conditional<
     693             :                                   Kind == mozilla::Cancelable,
     694             :                                   mozilla::CancelableRunnable,
     695             :                                   mozilla::IdleRunnable>::Type>::Type,
     696             :     protected mozilla::detail::TimerBehaviour<Kind>
     697             : {
     698             :   using BaseType = typename mozilla::Conditional<Kind == mozilla::Standard,
     699             :                                                  mozilla::Runnable,
     700             :                                                  typename mozilla::Conditional<
     701             :                                                    Kind == mozilla::Cancelable,
     702             :                                                    mozilla::CancelableRunnable,
     703             :                                                    mozilla::IdleRunnable>::Type>::Type;
     704             : public:
     705        1535 :   nsRunnableMethod() : BaseType("nsRunnableMethod") {}
     706             : 
     707             :   virtual void Revoke() = 0;
     708             : 
     709             :   // These ReturnTypeEnforcer classes set up a blacklist for return types that
     710             :   // we know are not safe. The default ReturnTypeEnforcer compiles just fine but
     711             :   // already_AddRefed will not.
     712             :   template<typename OtherReturnType>
     713             :   class ReturnTypeEnforcer
     714             :   {
     715             :   public:
     716             :     typedef int ReturnTypeIsSafe;
     717             :   };
     718             : 
     719             :   template<class T>
     720             :   class ReturnTypeEnforcer<already_AddRefed<T>>
     721             :   {
     722             :     // No ReturnTypeIsSafe makes this illegal!
     723             :   };
     724             : 
     725             :   // Make sure this return type is safe.
     726             :   typedef typename ReturnTypeEnforcer<ReturnType>::ReturnTypeIsSafe check;
     727             : };
     728             : 
     729             : template<class ClassType, bool Owning>
     730             : struct nsRunnableMethodReceiver
     731             : {
     732             :   RefPtr<ClassType> mObj;
     733        1053 :   explicit nsRunnableMethodReceiver(ClassType* aObj) : mObj(aObj) {}
     734        1018 :   ~nsRunnableMethodReceiver() { Revoke(); }
     735        2119 :   ClassType* Get() const { return mObj.get(); }
     736        2062 :   void Revoke() { mObj = nullptr; }
     737             : };
     738             : 
     739             : template<class ClassType>
     740             : struct nsRunnableMethodReceiver<ClassType, false>
     741             : {
     742             :   ClassType* MOZ_NON_OWNING_REF mObj;
     743         482 :   explicit nsRunnableMethodReceiver(ClassType* aObj) : mObj(aObj) {}
     744         930 :   ClassType* Get() const { return mObj; }
     745         446 :   void Revoke() { mObj = nullptr; }
     746             : };
     747             : 
     748             : static inline constexpr bool
     749             : IsIdle(mozilla::RunnableKind aKind)
     750             : {
     751             :   return aKind == mozilla::Idle || aKind == mozilla::IdleWithTimer;
     752             : }
     753             : 
     754             : template<typename PtrType, typename Method, bool Owning, mozilla::RunnableKind Kind>
     755             : struct nsRunnableMethodTraits;
     756             : 
     757             : template<typename PtrType, class C, typename R, bool Owning, mozilla::RunnableKind Kind, typename... As>
     758             : struct nsRunnableMethodTraits<PtrType, R(C::*)(As...), Owning, Kind>
     759             : {
     760             :   typedef typename mozilla::RemoveRawOrSmartPointer<PtrType>::Type class_type;
     761             :   static_assert(mozilla::IsBaseOf<C, class_type>::value,
     762             :                 "Stored class must inherit from method's class");
     763             :   typedef R return_type;
     764             :   typedef nsRunnableMethod<C, R, Owning, Kind> base_type;
     765             :   static const bool can_cancel = Kind == mozilla::Cancelable;
     766             : };
     767             : 
     768             : template<typename PtrType, class C, typename R, bool Owning, mozilla::RunnableKind Kind, typename... As>
     769             : struct nsRunnableMethodTraits<PtrType, R(C::*)(As...) const, Owning, Kind>
     770             : {
     771             :   typedef const typename mozilla::RemoveRawOrSmartPointer<PtrType>::Type class_type;
     772             :   static_assert(mozilla::IsBaseOf<C, class_type>::value,
     773             :                 "Stored class must inherit from method's class");
     774             :   typedef R return_type;
     775             :   typedef nsRunnableMethod<C, R, Owning, Kind> base_type;
     776             :   static const bool can_cancel = Kind == mozilla::Cancelable;
     777             : };
     778             : 
     779             : #ifdef NS_HAVE_STDCALL
     780             : template<typename PtrType, class C, typename R, bool Owning, mozilla::RunnableKind Kind, typename... As>
     781             : struct nsRunnableMethodTraits<PtrType, R(__stdcall C::*)(As...), Owning, Kind>
     782             : {
     783             :   typedef typename mozilla::RemoveRawOrSmartPointer<PtrType>::Type class_type;
     784             :   static_assert(mozilla::IsBaseOf<C, class_type>::value,
     785             :                 "Stored class must inherit from method's class");
     786             :   typedef R return_type;
     787             :   typedef nsRunnableMethod<C, R, Owning, Kind> base_type;
     788             :   static const bool can_cancel = Kind == mozilla::Cancelable;
     789             : };
     790             : 
     791             : template<typename PtrType, class C, typename R, bool Owning, mozilla::RunnableKind Kind>
     792             : struct nsRunnableMethodTraits<PtrType, R(NS_STDCALL C::*)(), Owning, Kind>
     793             : {
     794             :   typedef typename mozilla::RemoveRawOrSmartPointer<PtrType>::Type class_type;
     795             :   static_assert(mozilla::IsBaseOf<C, class_type>::value,
     796             :                 "Stored class must inherit from method's class");
     797             :   typedef R return_type;
     798             :   typedef nsRunnableMethod<C, R, Owning, Kind> base_type;
     799             :   static const bool can_cancel = Kind == mozilla::Cancelable;
     800             : };
     801             : 
     802             : template<typename PtrType, class C, typename R, bool Owning, mozilla::RunnableKind Kind, typename... As>
     803             : struct nsRunnableMethodTraits<PtrType, R(__stdcall C::*)(As...) const, Owning, Kind>
     804             : {
     805             :   typedef const typename mozilla::RemoveRawOrSmartPointer<PtrType>::Type class_type;
     806             :   static_assert(mozilla::IsBaseOf<C, class_type>::value,
     807             :                 "Stored class must inherit from method's class");
     808             :   typedef R return_type;
     809             :   typedef nsRunnableMethod<C, R, Owning, Kind> base_type;
     810             :   static const bool can_cancel = Kind == mozilla::Cancelable;
     811             : };
     812             : 
     813             : template<typename PtrType, class C, typename R, bool Owning, mozilla::RunnableKind Kind>
     814             : struct nsRunnableMethodTraits<PtrType, R(NS_STDCALL C::*)() const, Owning, Kind>
     815             : {
     816             :   typedef const typename mozilla::RemoveRawOrSmartPointer<PtrType>::Type class_type;
     817             :   static_assert(mozilla::IsBaseOf<C, class_type>::value,
     818             :                 "Stored class must inherit from method's class");
     819             :   typedef R return_type;
     820             :   typedef nsRunnableMethod<C, R, Owning, Kind> base_type;
     821             :   static const bool can_cancel = Kind == mozilla::Cancelable;
     822             : };
     823             : #endif
     824             : 
     825             : 
     826             : // IsParameterStorageClass<T>::value is true if T is a parameter-storage class
     827             : // that will be recognized by NS_New[NonOwning]RunnableMethodWithArg[s] to
     828             : // force a specific storage&passing strategy (instead of inferring one,
     829             : // see ParameterStorage).
     830             : // When creating a new storage class, add a specialization for it to be
     831             : // recognized.
     832             : template<typename T>
     833             : struct IsParameterStorageClass : public mozilla::FalseType {};
     834             : 
     835             : // StoreXPassByY structs used to inform nsRunnableMethodArguments how to
     836             : // store arguments, and how to pass them to the target method.
     837             : 
     838             : template<typename T>
     839             : struct StoreCopyPassByValue
     840             : {
     841             :   typedef T stored_type;
     842             :   typedef T passed_type;
     843             :   stored_type m;
     844             :   template <typename A>
     845             :   MOZ_IMPLICIT StoreCopyPassByValue(A&& a) : m(mozilla::Forward<A>(a)) {}
     846             :   passed_type PassAsParameter() { return m; }
     847             : };
     848             : template<typename S>
     849             : struct IsParameterStorageClass<StoreCopyPassByValue<S>>
     850             :   : public mozilla::TrueType {};
     851             : 
     852             : template<typename T>
     853          14 : struct StoreCopyPassByConstLRef
     854             : {
     855             :   typedef T stored_type;
     856             :   typedef const T& passed_type;
     857             :   stored_type m;
     858             :   template <typename A>
     859         813 :   MOZ_IMPLICIT StoreCopyPassByConstLRef(A&& a) : m(mozilla::Forward<A>(a)) {}
     860         806 :   passed_type PassAsParameter() { return m; }
     861             : };
     862             : template<typename S>
     863             : struct IsParameterStorageClass<StoreCopyPassByConstLRef<S>>
     864             :   : public mozilla::TrueType {};
     865             : 
     866             : template<typename T>
     867           0 : struct StoreCopyPassByLRef
     868             : {
     869             :   typedef T stored_type;
     870             :   typedef T& passed_type;
     871             :   stored_type m;
     872             :   template <typename A>
     873           0 :   MOZ_IMPLICIT StoreCopyPassByLRef(A&& a) : m(mozilla::Forward<A>(a)) {}
     874           0 :   passed_type PassAsParameter() { return m; }
     875             : };
     876             : template<typename S>
     877             : struct IsParameterStorageClass<StoreCopyPassByLRef<S>>
     878             :   : public mozilla::TrueType {};
     879             : 
     880             : template<typename T>
     881          16 : struct StoreCopyPassByRRef
     882             : {
     883             :   typedef T stored_type;
     884             :   typedef T&& passed_type;
     885             :   stored_type m;
     886             :   template <typename A>
     887          16 :   MOZ_IMPLICIT StoreCopyPassByRRef(A&& a) : m(mozilla::Forward<A>(a)) {}
     888          16 :   passed_type PassAsParameter() { return mozilla::Move(m); }
     889             : };
     890             : template<typename S>
     891             : struct IsParameterStorageClass<StoreCopyPassByRRef<S>>
     892             :   : public mozilla::TrueType {};
     893             : 
     894             : template<typename T>
     895             : struct StoreRefPassByLRef
     896             : {
     897             :   typedef T& stored_type;
     898             :   typedef T& passed_type;
     899             :   stored_type m;
     900             :   template <typename A>
     901             :   MOZ_IMPLICIT StoreRefPassByLRef(A& a) : m(a) {}
     902             :   passed_type PassAsParameter() { return m; }
     903             : };
     904             : template<typename S>
     905             : struct IsParameterStorageClass<StoreRefPassByLRef<S>>
     906             :   : public mozilla::TrueType {};
     907             : 
     908             : template<typename T>
     909             : struct StoreConstRefPassByConstLRef
     910             : {
     911             :   typedef const T& stored_type;
     912             :   typedef const T& passed_type;
     913             :   stored_type m;
     914             :   template <typename A>
     915           0 :   MOZ_IMPLICIT StoreConstRefPassByConstLRef(const A& a) : m(a) {}
     916           0 :   passed_type PassAsParameter() { return m; }
     917             : };
     918             : template<typename S>
     919             : struct IsParameterStorageClass<StoreConstRefPassByConstLRef<S>>
     920             :   : public mozilla::TrueType {};
     921             : 
     922             : template<typename T>
     923           8 : struct StoreRefPtrPassByPtr
     924             : {
     925             :   typedef RefPtr<T> stored_type;
     926             :   typedef T* passed_type;
     927             :   stored_type m;
     928             :   template <typename A>
     929           8 :   MOZ_IMPLICIT StoreRefPtrPassByPtr(A&& a) : m(mozilla::Forward<A>(a)) {}
     930           8 :   passed_type PassAsParameter() { return m.get(); }
     931             : };
     932             : template<typename S>
     933             : struct IsParameterStorageClass<StoreRefPtrPassByPtr<S>>
     934             :   : public mozilla::TrueType {};
     935             : 
     936             : template<typename T>
     937             : struct StorePtrPassByPtr
     938             : {
     939             :   typedef T* stored_type;
     940             :   typedef T* passed_type;
     941             :   stored_type m;
     942             :   template <typename A>
     943         365 :   MOZ_IMPLICIT StorePtrPassByPtr(A a) : m(a) {}
     944         369 :   passed_type PassAsParameter() { return m; }
     945             : };
     946             : template<typename S>
     947             : struct IsParameterStorageClass<StorePtrPassByPtr<S>>
     948             :   : public mozilla::TrueType {};
     949             : 
     950             : template<typename T>
     951             : struct StoreConstPtrPassByConstPtr
     952             : {
     953             :   typedef const T* stored_type;
     954             :   typedef const T* passed_type;
     955             :   stored_type m;
     956             :   template <typename A>
     957           3 :   MOZ_IMPLICIT StoreConstPtrPassByConstPtr(A a) : m(a) {}
     958           3 :   passed_type PassAsParameter() { return m; }
     959             : };
     960             : template<typename S>
     961             : struct IsParameterStorageClass<StoreConstPtrPassByConstPtr<S>>
     962             :   : public mozilla::TrueType {};
     963             : 
     964             : template<typename T>
     965             : struct StoreCopyPassByConstPtr
     966             : {
     967             :   typedef T stored_type;
     968             :   typedef const T* passed_type;
     969             :   stored_type m;
     970             :   template <typename A>
     971             :   MOZ_IMPLICIT StoreCopyPassByConstPtr(A&& a) : m(mozilla::Forward<A>(a)) {}
     972             :   passed_type PassAsParameter() { return &m; }
     973             : };
     974             : template<typename S>
     975             : struct IsParameterStorageClass<StoreCopyPassByConstPtr<S>>
     976             :   : public mozilla::TrueType {};
     977             : 
     978             : template<typename T>
     979             : struct StoreCopyPassByPtr
     980             : {
     981             :   typedef T stored_type;
     982             :   typedef T* passed_type;
     983             :   stored_type m;
     984             :   template <typename A>
     985             :   MOZ_IMPLICIT StoreCopyPassByPtr(A&& a) : m(mozilla::Forward<A>(a)) {}
     986             :   passed_type PassAsParameter() { return &m; }
     987             : };
     988             : template<typename S>
     989             : struct IsParameterStorageClass<StoreCopyPassByPtr<S>>
     990             :   : public mozilla::TrueType {};
     991             : 
     992             : namespace detail {
     993             : 
     994             : template<typename>
     995             : struct SFINAE1True : mozilla::TrueType
     996             : {};
     997             : 
     998             : template<class T>
     999             : static auto HasRefCountMethodsTest(int)
    1000             :     -> SFINAE1True<decltype(mozilla::DeclVal<T>().AddRef(),
    1001             :                             mozilla::DeclVal<T>().Release())>;
    1002             : template<class>
    1003             : static auto HasRefCountMethodsTest(long) -> mozilla::FalseType;
    1004             : 
    1005             : template<class T>
    1006             : struct HasRefCountMethods : decltype(HasRefCountMethodsTest<T>(0))
    1007             : {};
    1008             : 
    1009             : template<typename TWithoutPointer>
    1010             : struct NonnsISupportsPointerStorageClass
    1011             :   : mozilla::Conditional<mozilla::IsConst<TWithoutPointer>::value,
    1012             :                          StoreConstPtrPassByConstPtr<
    1013             :                            typename mozilla::RemoveConst<TWithoutPointer>::Type>,
    1014             :                          StorePtrPassByPtr<TWithoutPointer>>
    1015             : {};
    1016             : 
    1017             : template<typename TWithoutPointer>
    1018             : struct PointerStorageClass
    1019             :   : mozilla::Conditional<HasRefCountMethods<TWithoutPointer>::value,
    1020             :                          StoreRefPtrPassByPtr<TWithoutPointer>,
    1021             :                          typename NonnsISupportsPointerStorageClass<
    1022             :                            TWithoutPointer
    1023             :                          >::Type>
    1024             : {};
    1025             : 
    1026             : template<typename TWithoutRef>
    1027             : struct LValueReferenceStorageClass
    1028             :   : mozilla::Conditional<mozilla::IsConst<TWithoutRef>::value,
    1029             :                          StoreConstRefPassByConstLRef<
    1030             :                            typename mozilla::RemoveConst<TWithoutRef>::Type>,
    1031             :                          StoreRefPassByLRef<TWithoutRef>>
    1032             : {};
    1033             : 
    1034             : template<typename T>
    1035             : struct SmartPointerStorageClass
    1036             :   : mozilla::Conditional<mozilla::IsRefcountedSmartPointer<T>::value,
    1037             :                          StoreRefPtrPassByPtr<
    1038             :                            typename mozilla::RemoveSmartPointer<T>::Type>,
    1039             :                          StoreCopyPassByConstLRef<T>>
    1040             : {};
    1041             : 
    1042             : template<typename T>
    1043             : struct NonLValueReferenceStorageClass
    1044             :   : mozilla::Conditional<mozilla::IsRvalueReference<T>::value,
    1045             :                          StoreCopyPassByRRef<
    1046             :                            typename mozilla::RemoveReference<T>::Type>,
    1047             :                          typename SmartPointerStorageClass<T>::Type>
    1048             : {};
    1049             : 
    1050             : template<typename T>
    1051             : struct NonPointerStorageClass
    1052             :   : mozilla::Conditional<mozilla::IsLvalueReference<T>::value,
    1053             :                          typename LValueReferenceStorageClass<
    1054             :                            typename mozilla::RemoveReference<T>::Type
    1055             :                          >::Type,
    1056             :                          typename NonLValueReferenceStorageClass<T>::Type>
    1057             : {};
    1058             : 
    1059             : template<typename T>
    1060             : struct NonParameterStorageClass
    1061             :   : mozilla::Conditional<mozilla::IsPointer<T>::value,
    1062             :                          typename PointerStorageClass<
    1063             :                            typename mozilla::RemovePointer<T>::Type
    1064             :                          >::Type,
    1065             :                          typename NonPointerStorageClass<T>::Type>
    1066             : {};
    1067             : 
    1068             : // Choose storage&passing strategy based on preferred storage type:
    1069             : // - If IsParameterStorageClass<T>::value is true, use as-is.
    1070             : // - RC*       -> StoreRefPtrPassByPtr<RC>       : Store RefPtr<RC>, pass RC*
    1071             : //   ^^ RC quacks like a ref-counted type (i.e., has AddRef and Release methods)
    1072             : // - const T*  -> StoreConstPtrPassByConstPtr<T> : Store const T*, pass const T*
    1073             : // - T*        -> StorePtrPassByPtr<T>           : Store T*, pass T*.
    1074             : // - const T&  -> StoreConstRefPassByConstLRef<T>: Store const T&, pass const T&.
    1075             : // - T&        -> StoreRefPassByLRef<T>          : Store T&, pass T&.
    1076             : // - T&&       -> StoreCopyPassByRRef<T>         : Store T, pass Move(T).
    1077             : // - RefPtr<T>, nsCOMPtr<T>
    1078             : //             -> StoreRefPtrPassByPtr<T>        : Store RefPtr<T>, pass T*
    1079             : // - Other T   -> StoreCopyPassByConstLRef<T>    : Store T, pass const T&.
    1080             : // Other available explicit options:
    1081             : // -              StoreCopyPassByValue<T>        : Store T, pass T.
    1082             : // -              StoreCopyPassByLRef<T>         : Store T, pass T& (of copy!)
    1083             : // -              StoreCopyPassByConstPtr<T>     : Store T, pass const T*
    1084             : // -              StoreCopyPassByPtr<T>          : Store T, pass T* (of copy!)
    1085             : // Or create your own class with PassAsParameter() method, optional
    1086             : // clean-up in destructor, and with associated IsParameterStorageClass<>.
    1087             : template<typename T>
    1088             : struct ParameterStorage
    1089             :   : mozilla::Conditional<IsParameterStorageClass<T>::value,
    1090             :                          T,
    1091             :                          typename NonParameterStorageClass<T>::Type>
    1092             : {};
    1093             : 
    1094             : template<class T>
    1095             : static auto
    1096             : HasSetDeadlineTest(int) -> SFINAE1True<decltype(
    1097             :   mozilla::DeclVal<T>().SetDeadline(mozilla::DeclVal<mozilla::TimeStamp>()))>;
    1098             : 
    1099             : template<class T>
    1100             : static auto
    1101             : HasSetDeadlineTest(long) -> mozilla::FalseType;
    1102             : 
    1103             : template<class T>
    1104             : struct HasSetDeadline : decltype(HasSetDeadlineTest<T>(0))
    1105             : {};
    1106             : 
    1107             : template <class T>
    1108             : typename mozilla::EnableIf<::detail::HasSetDeadline<T>::value>::Type
    1109             : SetDeadlineImpl(T* aObj, mozilla::TimeStamp aTimeStamp)
    1110             : {
    1111             :   aObj->SetDeadline(aTimeStamp);
    1112             : }
    1113             : 
    1114             : template <class T>
    1115             : typename mozilla::EnableIf<!::detail::HasSetDeadline<T>::value>::Type
    1116             : SetDeadlineImpl(T* aObj, mozilla::TimeStamp aTimeStamp)
    1117             : {
    1118             : }
    1119             : } /* namespace detail */
    1120             : 
    1121             : namespace mozilla {
    1122             : namespace detail {
    1123             : 
    1124             : // struct used to store arguments and later apply them to a method.
    1125             : template <typename... Ts>
    1126          37 : struct RunnableMethodArguments final
    1127             : {
    1128             :   Tuple<typename ::detail::ParameterStorage<Ts>::Type...> mArguments;
    1129             :   template <typename... As>
    1130        1546 :   explicit RunnableMethodArguments(As&&... aArguments)
    1131        1164 :     : mArguments(Forward<As>(aArguments)...)
    1132        1546 :   {}
    1133             :   template<typename C, typename M, typename... Args, size_t... Indices>
    1134             :   static auto
    1135        1516 :   applyImpl(C* o, M m, Tuple<Args...>& args, IndexSequence<Indices...>)
    1136             :       -> decltype(((*o).*m)(Get<Indices>(args).PassAsParameter()...))
    1137             :   {
    1138        1516 :     return ((*o).*m)(Get<Indices>(args).PassAsParameter()...);
    1139             :   }
    1140        1516 :   template<class C, typename M> auto apply(C* o, M m)
    1141             :       -> decltype(applyImpl(o, m, mArguments,
    1142             :                   typename IndexSequenceFor<Ts...>::Type()))
    1143             :   {
    1144        3026 :     return applyImpl(o, m, mArguments,
    1145        3029 :         typename IndexSequenceFor<Ts...>::Type());
    1146             :   }
    1147             : };
    1148             : 
    1149             : template<typename PtrType, typename Method, bool Owning, RunnableKind Kind, typename... Storages>
    1150             : class RunnableMethodImpl final
    1151             :   : public ::nsRunnableMethodTraits<PtrType, Method, Owning, Kind>::base_type
    1152             : {
    1153             :   typedef typename ::nsRunnableMethodTraits<PtrType, Method, Owning, Kind> Traits;
    1154             : 
    1155             :   typedef typename Traits::class_type ClassType;
    1156             :   typedef typename Traits::base_type BaseType;
    1157             :   ::nsRunnableMethodReceiver<ClassType, Owning> mReceiver;
    1158             :   Method mMethod;
    1159             :   RunnableMethodArguments<Storages...> mArgs;
    1160             :   using BaseType::GetTimer;
    1161             :   using BaseType::CancelTimer;
    1162             : private:
    1163        4392 :   virtual ~RunnableMethodImpl() { Revoke(); };
    1164             :   static void TimedOut(nsITimer* aTimer, void* aClosure)
    1165             :   {
    1166             :     static_assert(IsIdle(Kind), "Don't use me!");
    1167             :     RefPtr<IdleRunnable> r = static_cast<IdleRunnable*>(aClosure);
    1168             :     r->SetDeadline(TimeStamp());
    1169             :     r->Run();
    1170             :     r->Cancel();
    1171             :   }
    1172             : public:
    1173             :   template<typename ForwardedPtrType, typename... Args>
    1174        1535 :   explicit RunnableMethodImpl(ForwardedPtrType&& aObj, Method aMethod,
    1175             :                               Args&&... aArgs)
    1176        1535 :     : mReceiver(Forward<ForwardedPtrType>(aObj))
    1177             :     , mMethod(aMethod)
    1178        3070 :     , mArgs(Forward<Args>(aArgs)...)
    1179             :   {
    1180             :     static_assert(sizeof...(Storages) == sizeof...(Args), "Storages and Args should have equal sizes");
    1181        1535 :   }
    1182        1536 :   NS_IMETHOD Run()
    1183             :   {
    1184        1536 :     CancelTimer();
    1185             : 
    1186        1536 :     if (MOZ_LIKELY(mReceiver.Get())) {
    1187        1513 :       mArgs.apply(mReceiver.Get(), mMethod);
    1188             :     }
    1189             : 
    1190        1536 :     return NS_OK;
    1191             :   }
    1192             : 
    1193           3 :   nsresult Cancel()
    1194             :   {
    1195             :     static_assert(Kind >= Cancelable, "Don't use me!");
    1196           3 :     Revoke();
    1197           3 :     return NS_OK;
    1198             :   }
    1199             : 
    1200        1490 :   void Revoke()
    1201             :   {
    1202        1490 :     CancelTimer();
    1203        1490 :     mReceiver.Revoke();
    1204        1490 :   }
    1205             : 
    1206             :   void SetDeadline(TimeStamp aDeadline)
    1207             :   {
    1208             :     if (MOZ_LIKELY(mReceiver.Get())) {
    1209             :       ::detail::SetDeadlineImpl(mReceiver.Get(), aDeadline);
    1210             :     }
    1211             :   }
    1212             : 
    1213             :   void SetTimer(uint32_t aDelay, nsIEventTarget* aTarget)
    1214             :   {
    1215             :     MOZ_ASSERT(aTarget);
    1216             : 
    1217             :     if (nsCOMPtr<nsITimer> timer = GetTimer()) {
    1218             :       timer->Cancel();
    1219             :       timer->SetTarget(aTarget);
    1220             :       timer->InitWithNamedFuncCallback(TimedOut,
    1221             :                                        this,
    1222             :                                        aDelay,
    1223             :                                        nsITimer::TYPE_ONE_SHOT,
    1224             :                                        "detail::RunnableMethodImpl::SetTimer");
    1225             :     }
    1226             :   }
    1227             : };
    1228             : 
    1229             : // Type aliases for NewRunnableMethod.
    1230             : template<typename PtrType, typename Method>
    1231             : using OwningRunnableMethod = typename ::nsRunnableMethodTraits<
    1232             :   typename RemoveReference<PtrType>::Type, Method, true, Standard>::base_type;
    1233             : template<typename PtrType, typename Method, typename... Storages>
    1234             : using OwningRunnableMethodImpl = RunnableMethodImpl<
    1235             :   typename RemoveReference<PtrType>::Type, Method, true, Standard, Storages...>;
    1236             : 
    1237             : // Type aliases for NewCancelableRunnableMethod.
    1238             : template<typename PtrType, typename Method>
    1239             : using CancelableRunnableMethod = typename ::nsRunnableMethodTraits<
    1240             :   typename RemoveReference<PtrType>::Type, Method, true, Cancelable>::base_type;
    1241             : template<typename PtrType, typename Method, typename... Storages>
    1242             : using CancelableRunnableMethodImpl = RunnableMethodImpl<
    1243             :   typename RemoveReference<PtrType>::Type, Method, true, Cancelable, Storages...>;
    1244             : 
    1245             : // Type aliases for NewIdleRunnableMethod.
    1246             : template<typename PtrType, typename Method>
    1247             : using IdleRunnableMethod = typename ::nsRunnableMethodTraits<
    1248             :   typename RemoveReference<PtrType>::Type, Method, true, Idle>::base_type;
    1249             : template<typename PtrType, typename Method, typename... Storages>
    1250             : using IdleRunnableMethodImpl = RunnableMethodImpl<
    1251             :   typename RemoveReference<PtrType>::Type, Method, true, Idle, Storages...>;
    1252             : 
    1253             : // Type aliases for NewIdleRunnableMethodWithTimer.
    1254             : template<typename PtrType, typename Method>
    1255             : using IdleRunnableMethodWithTimer = typename ::nsRunnableMethodTraits<
    1256             :   typename RemoveReference<PtrType>::Type, Method, true, IdleWithTimer>::base_type;
    1257             : template<typename PtrType, typename Method, typename... Storages>
    1258             : using IdleRunnableMethodWithTimerImpl = RunnableMethodImpl<
    1259             :   typename RemoveReference<PtrType>::Type, Method, true, IdleWithTimer, Storages...>;
    1260             : 
    1261             : // Type aliases for NewNonOwningRunnableMethod.
    1262             : template<typename PtrType, typename Method>
    1263             : using NonOwningRunnableMethod = typename ::nsRunnableMethodTraits<
    1264             :   typename RemoveReference<PtrType>::Type, Method, false, Standard>::base_type;
    1265             : template<typename PtrType, typename Method, typename... Storages>
    1266             : using NonOwningRunnableMethodImpl = RunnableMethodImpl<
    1267             :   typename RemoveReference<PtrType>::Type, Method, false, Standard, Storages...>;
    1268             : 
    1269             : // Type aliases for NonOwningCancelableRunnableMethod
    1270             : template<typename PtrType, typename Method>
    1271             : using NonOwningCancelableRunnableMethod = typename ::nsRunnableMethodTraits<
    1272             :   typename RemoveReference<PtrType>::Type, Method, false, Cancelable>::base_type;
    1273             : template<typename PtrType, typename Method, typename... Storages>
    1274             : using NonOwningCancelableRunnableMethodImpl = RunnableMethodImpl<
    1275             :   typename RemoveReference<PtrType>::Type, Method, false, Cancelable, Storages...>;
    1276             : 
    1277             : // Type aliases for NonOwningIdleRunnableMethod
    1278             : template<typename PtrType, typename Method>
    1279             : using NonOwningIdleRunnableMethod = typename ::nsRunnableMethodTraits<
    1280             :   typename RemoveReference<PtrType>::Type, Method, false, Idle>::base_type;
    1281             : template<typename PtrType, typename Method, typename... Storages>
    1282             : using NonOwningIdleRunnableMethodImpl = RunnableMethodImpl<
    1283             :   typename RemoveReference<PtrType>::Type, Method, false, Idle, Storages...>;
    1284             : 
    1285             : // Type aliases for NewIdleRunnableMethodWithTimer.
    1286             : template<typename PtrType, typename Method>
    1287             : using NonOwningIdleRunnableMethodWithTimer = typename ::nsRunnableMethodTraits<
    1288             :   typename RemoveReference<PtrType>::Type, Method, false, IdleWithTimer>::base_type;
    1289             : template<typename PtrType, typename Method, typename... Storages>
    1290             : using NonOwningIdleRunnableMethodWithTimerImpl = RunnableMethodImpl<
    1291             :   typename RemoveReference<PtrType>::Type, Method, false, IdleWithTimer, Storages...>;
    1292             : 
    1293             : } // namespace detail
    1294             : 
    1295             : // NewRunnableMethod and friends
    1296             : //
    1297             : // Very often in Gecko, you'll find yourself in a situation where you want
    1298             : // to invoke a method (with or without arguments) asynchronously.  You
    1299             : // could write a small helper class inheriting from nsRunnable to handle
    1300             : // all these details, or you could let NewRunnableMethod take care of all
    1301             : // those details for you.
    1302             : //
    1303             : // The simplest use of NewRunnableMethod looks like:
    1304             : //
    1305             : //   nsCOMPtr<nsIRunnable> event =
    1306             : //     mozilla::NewRunnableMethod("description", myObject, &MyClass::HandleEvent);
    1307             : //   NS_DispatchToCurrentThread(event);
    1308             : //
    1309             : // Statically enforced constraints:
    1310             : //  - myObject must be of (or implicitly convertible to) type MyClass
    1311             : //  - MyClass must define AddRef and Release methods
    1312             : //
    1313             : // The "description" string should specify a human-readable name for the
    1314             : // runnable; the provided string is used by various introspection tools
    1315             : // in the browser.
    1316             : //
    1317             : // The created runnable will take a strong reference to `myObject`.  For
    1318             : // non-refcounted objects, or refcounted objects with unusual refcounting
    1319             : // requirements, and if and only if you are 110% certain that `myObject`
    1320             : // will live long enough, you can use NewNonOwningRunnableMethod instead,
    1321             : // which will, as its name implies, take a non-owning reference.  If you
    1322             : // find yourself having to use this function, you should accompany your use
    1323             : // with a proof comment describing why the runnable will not lead to
    1324             : // use-after-frees.
    1325             : //
    1326             : // (If you find yourself writing contorted code to Release() an object
    1327             : // asynchronously on a different thread, you should use the
    1328             : // NS_ProxyRelease function.)
    1329             : //
    1330             : // Invoking a method with arguments takes a little more care.  The
    1331             : // natural extension of the above:
    1332             : //
    1333             : //   nsCOMPtr<nsIRunnable> event =
    1334             : //     mozilla::NewRunnableMethod("description", myObject, &MyClass::HandleEvent,
    1335             : //                                arg1, arg2, ...);
    1336             : //
    1337             : // can lead to security hazards (e.g. passing in raw pointers to refcounted
    1338             : // objects and storing those raw pointers in the runnable).  We therefore
    1339             : // require you to specify the storage types used by the runnable, just as
    1340             : // you would if you were writing out the class by hand:
    1341             : //
    1342             : //   nsCOMPtr<nsIRunnable> event =
    1343             : //     mozilla::NewRunnableMethod<RefPtr<T>, nsTArray<U>>
    1344             : //         ("description", myObject, &MyClass::HandleEvent, arg1, arg2);
    1345             : //
    1346             : // Please note that you do not have to pass the same argument type as you
    1347             : // specify in the template arguments.  For example, if you want to transfer
    1348             : // ownership to a runnable, you can write:
    1349             : //
    1350             : //   RefPtr<T> ptr = ...;
    1351             : //   nsTArray<U> array = ...;
    1352             : //   nsCOMPtr<nsIRunnable> event =
    1353             : //     mozilla::NewRunnableMethod<RefPtr<T>, nsTArray<U>>
    1354             : //         ("description", myObject, &MyClass::DoSomething,
    1355             : //          Move(ptr), Move(array));
    1356             : //
    1357             : // and there will be no extra AddRef/Release traffic, or copying of the array.
    1358             : //
    1359             : // Each type that you specify as a template argument to NewRunnableMethod
    1360             : // comes with its own style of storage in the runnable and its own style
    1361             : // of argument passing to the invoked method.  See the comment for
    1362             : // ParameterStorage above for more details.
    1363             : //
    1364             : // If you need to customize the storage type and/or argument passing type,
    1365             : // you can write your own class to use as a template argument to
    1366             : // NewRunnableMethod.  If you find yourself having to do that frequently,
    1367             : // please file a bug in Core::XPCOM about adding the custom type to the
    1368             : // core code in this file, and/or for custom rules for ParameterStorage
    1369             : // to select that strategy.
    1370             : //
    1371             : // For places that require you to use cancelable runnables, such as
    1372             : // workers, there's also NewCancelableRunnableMethod and its non-owning
    1373             : // counterpart.  The runnables returned by these methods additionally
    1374             : // implement nsICancelableRunnable.
    1375             : //
    1376             : // Finally, all of the functions discussed above have additional overloads
    1377             : // that do not take a `const char*` as their first parameter; you may see
    1378             : // these in older code.  The `const char*` overload is preferred and
    1379             : // should be used in new code exclusively.
    1380             : 
    1381             : template<typename PtrType, typename Method>
    1382             : already_AddRefed<detail::OwningRunnableMethod<PtrType, Method>>
    1383         272 : NewRunnableMethod(const char* aName, PtrType&& aPtr, Method aMethod)
    1384             : {
    1385             :   return detail::SetRunnableName(
    1386             :     aName,
    1387         272 :     new detail::OwningRunnableMethodImpl<PtrType, Method>(
    1388         544 :       Forward<PtrType>(aPtr), aMethod));
    1389             : }
    1390             : 
    1391             : template<typename PtrType, typename Method>
    1392             : already_AddRefed<detail::CancelableRunnableMethod<PtrType, Method>>
    1393           0 : NewCancelableRunnableMethod(const char* aName, PtrType&& aPtr, Method aMethod)
    1394             : {
    1395             :   return detail::SetRunnableName(
    1396             :     aName,
    1397           0 :     new detail::CancelableRunnableMethodImpl<PtrType, Method>(
    1398           0 :       Forward<PtrType>(aPtr), aMethod));
    1399             : }
    1400             : 
    1401             : template<typename PtrType, typename Method>
    1402             : already_AddRefed<detail::IdleRunnableMethod<PtrType, Method>>
    1403             : NewIdleRunnableMethod(const char* aName, PtrType&& aPtr, Method aMethod)
    1404             : {
    1405             :   return detail::SetRunnableName(
    1406             :     aName,
    1407             :     new detail::IdleRunnableMethodImpl<PtrType, Method>(
    1408             :       Forward<PtrType>(aPtr), aMethod));
    1409             : }
    1410             : 
    1411             : template<typename PtrType, typename Method>
    1412             : already_AddRefed<detail::IdleRunnableMethodWithTimer<PtrType, Method>>
    1413             : NewIdleRunnableMethodWithTimer(const char* aName,
    1414             :                                PtrType&& aPtr,
    1415             :                                Method aMethod)
    1416             : {
    1417             :   return detail::SetRunnableName(
    1418             :     aName,
    1419             :     new detail::IdleRunnableMethodWithTimerImpl<PtrType, Method>(
    1420             :       Forward<PtrType>(aPtr), aMethod));
    1421             : }
    1422             : 
    1423             : template<typename PtrType, typename Method>
    1424             : already_AddRefed<detail::NonOwningRunnableMethod<PtrType, Method>>
    1425          69 : NewNonOwningRunnableMethod(const char* aName, PtrType&& aPtr, Method aMethod)
    1426             : {
    1427             :   return detail::SetRunnableName(
    1428             :     aName,
    1429          69 :     new detail::NonOwningRunnableMethodImpl<PtrType, Method>(
    1430         138 :       Forward<PtrType>(aPtr), aMethod));
    1431             : }
    1432             : 
    1433             : template<typename PtrType, typename Method>
    1434             : already_AddRefed<detail::NonOwningCancelableRunnableMethod<PtrType, Method>>
    1435          40 : NewNonOwningCancelableRunnableMethod(const char* aName, PtrType&& aPtr,
    1436             :                                      Method aMethod)
    1437             : {
    1438             :   return detail::SetRunnableName(
    1439             :     aName,
    1440          40 :     new detail::NonOwningCancelableRunnableMethodImpl<PtrType, Method>(
    1441          80 :       Forward<PtrType>(aPtr), aMethod));
    1442             : }
    1443             : 
    1444             : template<typename PtrType, typename Method>
    1445             : already_AddRefed<detail::NonOwningIdleRunnableMethod<PtrType, Method>>
    1446             : NewNonOwningIdleRunnableMethod(const char* aName,
    1447             :                                PtrType&& aPtr,
    1448             :                                Method aMethod)
    1449             : {
    1450             :   return detail::SetRunnableName(
    1451             :     aName,
    1452             :     new detail::NonOwningIdleRunnableMethodImpl<PtrType, Method>(
    1453             :       Forward<PtrType>(aPtr), aMethod));
    1454             : }
    1455             : 
    1456             : template<typename PtrType, typename Method>
    1457             : already_AddRefed<detail::NonOwningIdleRunnableMethodWithTimer<PtrType, Method>>
    1458             : NewNonOwningIdleRunnableMethodWithTimer(const char* aName,
    1459             :                                         PtrType&& aPtr,
    1460             :                                         Method aMethod)
    1461             : {
    1462             :   return detail::SetRunnableName(
    1463             :     aName,
    1464             :     new detail::NonOwningIdleRunnableMethodWithTimerImpl<PtrType, Method>(
    1465             :       Forward<PtrType>(aPtr), aMethod));
    1466             : }
    1467             : 
    1468             : // Similar to NewRunnableMethod. Call like so:
    1469             : // nsCOMPtr<nsIRunnable> event =
    1470             : //   NewRunnableMethod<Types,...>(myObject, &MyClass::HandleEvent, myArg1,...);
    1471             : // 'Types' are the stored type for each argument, see ParameterStorage for details.
    1472             : template<typename... Storages, typename PtrType, typename Method, typename... Args>
    1473             : already_AddRefed<detail::OwningRunnableMethod<PtrType, Method>>
    1474         111 : NewRunnableMethod(const char* aName, PtrType&& aPtr, Method aMethod, Args&&... aArgs)
    1475             : {
    1476             :   static_assert(sizeof...(Storages) == sizeof...(Args),
    1477             :                 "<Storages...> size should be equal to number of arguments");
    1478             :   return detail::SetRunnableName(
    1479             :     aName,
    1480         111 :     new detail::OwningRunnableMethodImpl<PtrType, Method, Storages...>(
    1481         222 :       Forward<PtrType>(aPtr), aMethod, mozilla::Forward<Args>(aArgs)...));
    1482             : }
    1483             : 
    1484             : template<typename... Storages, typename PtrType, typename Method, typename... Args>
    1485             : already_AddRefed<detail::NonOwningRunnableMethod<PtrType, Method>>
    1486         373 : NewNonOwningRunnableMethod(const char* aName, PtrType&& aPtr, Method aMethod,
    1487             :                            Args&&... aArgs)
    1488             : {
    1489             :   static_assert(sizeof...(Storages) == sizeof...(Args),
    1490             :                 "<Storages...> size should be equal to number of arguments");
    1491             :   return detail::SetRunnableName(
    1492             :     aName,
    1493         373 :     new detail::NonOwningRunnableMethodImpl<PtrType, Method, Storages...>(
    1494         746 :       Forward<PtrType>(aPtr), aMethod, mozilla::Forward<Args>(aArgs)...));
    1495             : }
    1496             : 
    1497             : template<typename... Storages, typename PtrType, typename Method, typename... Args>
    1498             : already_AddRefed<detail::CancelableRunnableMethod<PtrType, Method>>
    1499         670 : NewCancelableRunnableMethod(const char* aName, PtrType&& aPtr, Method aMethod,
    1500             :                             Args&&... aArgs)
    1501             : {
    1502             :   static_assert(sizeof...(Storages) == sizeof...(Args),
    1503             :                 "<Storages...> size should be equal to number of arguments");
    1504             :   return detail::SetRunnableName(
    1505             :     aName,
    1506         670 :     new detail::CancelableRunnableMethodImpl<PtrType, Method, Storages...>(
    1507        1340 :       Forward<PtrType>(aPtr), aMethod, mozilla::Forward<Args>(aArgs)...));
    1508             : }
    1509             : 
    1510             : template<typename... Storages, typename PtrType, typename Method, typename... Args>
    1511             : already_AddRefed<detail::NonOwningCancelableRunnableMethod<PtrType, Method>>
    1512           0 : NewNonOwningCancelableRunnableMethod(const char* aName, PtrType&& aPtr,
    1513             :                                      Method aMethod, Args&&... aArgs)
    1514             : {
    1515             :   static_assert(sizeof...(Storages) == sizeof...(Args),
    1516             :                 "<Storages...> size should be equal to number of arguments");
    1517             :   return detail::SetRunnableName(
    1518             :     aName,
    1519           0 :     new detail::NonOwningCancelableRunnableMethodImpl<PtrType, Method, Storages...>(
    1520           0 :       Forward<PtrType>(aPtr), aMethod, mozilla::Forward<Args>(aArgs)...));
    1521             : }
    1522             : 
    1523             : template<typename... Storages,
    1524             :          typename PtrType,
    1525             :          typename Method,
    1526             :          typename... Args>
    1527             : already_AddRefed<detail::IdleRunnableMethod<PtrType, Method>>
    1528             : NewIdleRunnableMethod(const char* aName,
    1529             :                       PtrType&& aPtr,
    1530             :                       Method aMethod,
    1531             :                       Args&&... aArgs)
    1532             : {
    1533             :   static_assert(sizeof...(Storages) == sizeof...(Args),
    1534             :                 "<Storages...> size should be equal to number of arguments");
    1535             :   return detail::SetRunnableName(
    1536             :     aName,
    1537             :     new detail::IdleRunnableMethodImpl<PtrType, Method, Storages...>(
    1538             :       Forward<PtrType>(aPtr), aMethod, mozilla::Forward<Args>(aArgs)...));
    1539             : }
    1540             : 
    1541             : template<typename... Storages,
    1542             :          typename PtrType,
    1543             :          typename Method,
    1544             :          typename... Args>
    1545             : already_AddRefed<detail::NonOwningIdleRunnableMethod<PtrType, Method>>
    1546             : NewNonOwningIdleRunnableMethod(const char* aName,
    1547             :                                PtrType&& aPtr,
    1548             :                                Method aMethod,
    1549             :                                Args&&... aArgs)
    1550             : {
    1551             :   static_assert(sizeof...(Storages) == sizeof...(Args),
    1552             :                 "<Storages...> size should be equal to number of arguments");
    1553             :   return detail::SetRunnableName(
    1554             :     aName,
    1555             :     new detail::NonOwningIdleRunnableMethodImpl<PtrType, Method, Storages...>(
    1556             :       Forward<PtrType>(aPtr), aMethod, mozilla::Forward<Args>(aArgs)...));
    1557             : }
    1558             : 
    1559             : } // namespace mozilla
    1560             : 
    1561             : #endif  // XPCOM_GLUE_AVOID_NSPR
    1562             : 
    1563             : // This class is designed to be used when you have an event class E that has a
    1564             : // pointer back to resource class R.  If R goes away while E is still pending,
    1565             : // then it is important to "revoke" E so that it does not try use R after R has
    1566             : // been destroyed.  nsRevocableEventPtr makes it easy for R to manage such
    1567             : // situations:
    1568             : //
    1569             : //   class R;
    1570             : //
    1571             : //   class E : public mozilla::Runnable {
    1572             : //   public:
    1573             : //     void Revoke() {
    1574             : //       mResource = nullptr;
    1575             : //     }
    1576             : //   private:
    1577             : //     R *mResource;
    1578             : //   };
    1579             : //
    1580             : //   class R {
    1581             : //   public:
    1582             : //     void EventHandled() {
    1583             : //       mEvent.Forget();
    1584             : //     }
    1585             : //   private:
    1586             : //     nsRevocableEventPtr<E> mEvent;
    1587             : //   };
    1588             : //
    1589             : //   void R::PostEvent() {
    1590             : //     // Make sure any pending event is revoked.
    1591             : //     mEvent->Revoke();
    1592             : //
    1593             : //     nsCOMPtr<nsIRunnable> event = new E();
    1594             : //     if (NS_SUCCEEDED(NS_DispatchToCurrentThread(event))) {
    1595             : //       // Keep pointer to event so we can revoke it.
    1596             : //       mEvent = event;
    1597             : //     }
    1598             : //   }
    1599             : //
    1600             : //   NS_IMETHODIMP E::Run() {
    1601             : //     if (!mResource)
    1602             : //       return NS_OK;
    1603             : //     ...
    1604             : //     mResource->EventHandled();
    1605             : //     return NS_OK;
    1606             : //   }
    1607             : //
    1608             : template<class T>
    1609             : class nsRevocableEventPtr
    1610             : {
    1611             : public:
    1612         609 :   nsRevocableEventPtr() : mEvent(nullptr) {}
    1613          28 :   ~nsRevocableEventPtr() { Revoke(); }
    1614             : 
    1615         138 :   const nsRevocableEventPtr& operator=(T* aEvent)
    1616             :   {
    1617         138 :     if (mEvent != aEvent) {
    1618          89 :       Revoke();
    1619          89 :       mEvent = aEvent;
    1620             :     }
    1621         138 :     return *this;
    1622             :   }
    1623             : 
    1624           2 :   const nsRevocableEventPtr& operator=(already_AddRefed<T> aEvent)
    1625             :   {
    1626           4 :     RefPtr<T> event = aEvent;
    1627           2 :     if (mEvent != event) {
    1628           2 :       Revoke();
    1629           2 :       mEvent = event.forget();
    1630             :     }
    1631           4 :     return *this;
    1632             :   }
    1633             : 
    1634         167 :   void Revoke()
    1635             :   {
    1636         167 :     if (mEvent) {
    1637          29 :       mEvent->Revoke();
    1638          29 :       mEvent = nullptr;
    1639             :     }
    1640         167 :   }
    1641             : 
    1642          59 :   void Forget() { mEvent = nullptr; }
    1643         375 :   bool IsPending() { return mEvent != nullptr; }
    1644          61 :   T* get() { return mEvent; }
    1645             : 
    1646             : private:
    1647             :   // Not implemented
    1648             :   nsRevocableEventPtr(const nsRevocableEventPtr&);
    1649             :   nsRevocableEventPtr& operator=(const nsRevocableEventPtr&);
    1650             : 
    1651             :   RefPtr<T> mEvent;
    1652             : };
    1653             : 
    1654             : /**
    1655             :  * A simple helper to suffix thread pool name
    1656             :  * with incremental numbers.
    1657             :  */
    1658             : class nsThreadPoolNaming
    1659             : {
    1660             : public:
    1661          11 :   nsThreadPoolNaming() : mCounter(0) {}
    1662             : 
    1663             :   /**
    1664             :    * Returns a thread name as "<aPoolName> #<n>" and increments the counter.
    1665             :    */
    1666             :   nsCString GetNextThreadName(const nsACString& aPoolName);
    1667             : 
    1668             :   template<size_t LEN>
    1669          24 :   nsCString GetNextThreadName(const char (&aPoolName)[LEN])
    1670             :   {
    1671          24 :     return GetNextThreadName(nsDependentCString(aPoolName, LEN - 1));
    1672             :   }
    1673             : 
    1674             : private:
    1675             :   mozilla::Atomic<uint32_t> mCounter;
    1676             : 
    1677             :   nsThreadPoolNaming(const nsThreadPoolNaming&) = delete;
    1678             :   void operator=(const nsThreadPoolNaming&) = delete;
    1679             : };
    1680             : 
    1681             : /**
    1682             :  * Thread priority in most operating systems affect scheduling, not IO.  This
    1683             :  * helper is used to set the current thread to low IO priority for the lifetime
    1684             :  * of the created object.  You can only use this low priority IO setting within
    1685             :  * the context of the current thread.
    1686             :  */
    1687             : class MOZ_STACK_CLASS nsAutoLowPriorityIO
    1688             : {
    1689             : public:
    1690             :   nsAutoLowPriorityIO();
    1691             :   ~nsAutoLowPriorityIO();
    1692             : 
    1693             : private:
    1694             :   bool lowIOPrioritySet;
    1695             : #if defined(XP_MACOSX)
    1696             :   int oldPriority;
    1697             : #endif
    1698             : };
    1699             : 
    1700             : void
    1701             : NS_SetMainThread();
    1702             : 
    1703             : /**
    1704             :  * Return the expiration time of the next timer to run on the current
    1705             :  * thread.  If that expiration time is greater than aDefault, then
    1706             :  * return aDefault.  aSearchBound specifies a maximum number of timers
    1707             :  * to examine to find a timer on the current thread.  If no timer that
    1708             :  * will run on the current thread is found after examining
    1709             :  * aSearchBound timers, return the highest seen expiration time as a
    1710             :  * best effort guess.
    1711             :  *
    1712             :  * Timers with either the type nsITimer::TYPE_ONE_SHOT_LOW_PRIORITY or
    1713             :  * nsITIMER::TYPE_REPEATING_SLACK_LOW_PRIORITY will be skipped when
    1714             :  * searching for the next expiration time.  This enables timers to
    1715             :  * have lower priority than callbacks dispatched from
    1716             :  * nsIThread::IdleDispatch.
    1717             :  */
    1718             : extern mozilla::TimeStamp
    1719             : NS_GetTimerDeadlineHintOnCurrentThread(mozilla::TimeStamp aDefault, uint32_t aSearchBound);
    1720             : 
    1721             : namespace mozilla {
    1722             : 
    1723             : /**
    1724             :  * Cooperative thread scheduling is governed by two rules:
    1725             :  * - Only one thread in the pool of cooperatively scheduled threads runs at a
    1726             :  *   time.
    1727             :  * - Thread switching happens at well-understood safe points.
    1728             :  *
    1729             :  * In some cases we may want to treat all the threads in a cooperative pool as a
    1730             :  * single thread, while other parts of the code may want to view them as separate
    1731             :  * threads. GetCurrentVirtualThread() will return the same value for all
    1732             :  * threads in a cooperative thread pool. GetCurrentPhysicalThread will return a
    1733             :  * different value for each thread in the pool.
    1734             :  *
    1735             :  * Thread safety assertions are a concrete example where GetCurrentVirtualThread
    1736             :  * should be used. An object may want to assert that it only can be used on the
    1737             :  * thread that created it. Such assertions would normally prevent the object
    1738             :  * from being used on different cooperative threads. However, the object might
    1739             :  * really only care that it's used atomically. Cooperative scheduling guarantees
    1740             :  * that it will be (assuming we don't yield in the middle of modifying the
    1741             :  * object). So we can weaken the assertion to compare the virtual thread the
    1742             :  * object was created on to the virtual thread on which it's being used. This
    1743             :  * assertion allows the object to be used across threads in a cooperative thread
    1744             :  * pool while preventing accesses across preemptively scheduled threads (which
    1745             :  * would be unsafe).
    1746             :  */
    1747             : 
    1748             : // Returns the PRThread on which this code is running.
    1749             : PRThread*
    1750             : GetCurrentPhysicalThread();
    1751             : 
    1752             : // Returns a "virtual" PRThread that should only be used for comparison with
    1753             : // other calls to GetCurrentVirtualThread. Two threads in the same cooperative
    1754             : // thread pool will return the same virtual thread. Threads that are not
    1755             : // cooperatively scheduled will have their own unique virtual PRThread (which
    1756             : // will be equal to their physical PRThread).
    1757             : //
    1758             : // The return value of GetCurrentVirtualThread() is guaranteed not to change
    1759             : // throughout the lifetime of a thread.
    1760             : //
    1761             : // Note that the original main thread (the first one created in the process) is
    1762             : // considered as part of the pool of cooperative threads, so the return value of
    1763             : // GetCurrentVirtualThread() for this thread (throughout its lifetime, even
    1764             : // during shutdown) is the same as the return value from any other thread in the
    1765             : // cooperative pool.
    1766             : PRThread*
    1767             : GetCurrentVirtualThread();
    1768             : 
    1769             : // These functions return event targets that can be used to dispatch to the
    1770             : // current or main thread. They can also be used to test if you're on those
    1771             : // threads (via IsOnCurrentThread). These functions should be used in preference
    1772             : // to the nsIThread-based NS_Get{Current,Main}Thread functions since they will
    1773             : // return more useful answers in the case of threads sharing an event loop.
    1774             : 
    1775             : nsIEventTarget*
    1776             : GetCurrentThreadEventTarget();
    1777             : 
    1778             : nsIEventTarget*
    1779             : GetMainThreadEventTarget();
    1780             : 
    1781             : // These variants of the above functions assert that the given thread has a
    1782             : // serial event target (i.e., that it's not part of a thread pool) and returns
    1783             : // that.
    1784             : 
    1785             : nsISerialEventTarget*
    1786             : GetCurrentThreadSerialEventTarget();
    1787             : 
    1788             : nsISerialEventTarget*
    1789             : GetMainThreadSerialEventTarget();
    1790             : 
    1791             : } // namespace mozilla
    1792             : 
    1793             : #endif  // nsThreadUtils_h__

Generated by: LCOV version 1.13