LCOV - code coverage report
Current view: top level - xpcom/threads - nsThread.h (source / functions) Hit Total Coverage
Test: output.info Lines: 41 43 95.3 %
Date: 2017-07-14 16:53:18 Functions: 10 11 90.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 nsThread_h__
       8             : #define nsThread_h__
       9             : 
      10             : #include "mozilla/Mutex.h"
      11             : #include "nsIIdlePeriod.h"
      12             : #include "nsIThreadInternal.h"
      13             : #include "nsISupportsPriority.h"
      14             : #include "nsEventQueue.h"
      15             : #include "nsThreadUtils.h"
      16             : #include "nsString.h"
      17             : #include "nsTObserverArray.h"
      18             : #include "mozilla/Attributes.h"
      19             : #include "mozilla/NotNull.h"
      20             : #include "mozilla/TimeStamp.h"
      21             : #include "nsAutoPtr.h"
      22             : #include "mozilla/AlreadyAddRefed.h"
      23             : #include "mozilla/UniquePtr.h"
      24             : 
      25             : namespace mozilla {
      26             : class CycleCollectedJSContext;
      27             : }
      28             : 
      29             : using mozilla::NotNull;
      30             : 
      31             : // A native thread
      32             : class nsThread
      33             :   : public nsIThreadInternal
      34             :   , public nsISupportsPriority
      35             : {
      36             : public:
      37             :   NS_DECL_THREADSAFE_ISUPPORTS
      38             :   NS_DECL_NSIEVENTTARGET_FULL
      39             :   NS_DECL_NSITHREAD
      40             :   NS_DECL_NSITHREADINTERNAL
      41             :   NS_DECL_NSISUPPORTSPRIORITY
      42             : 
      43             :   enum MainThreadFlag
      44             :   {
      45             :     MAIN_THREAD,
      46             :     NOT_MAIN_THREAD
      47             :   };
      48             : 
      49             :   nsThread(MainThreadFlag aMainThread, uint32_t aStackSize);
      50             : 
      51             :   // Initialize this as a wrapper for a new PRThread, and optionally give it a name.
      52             :   nsresult Init(const nsACString& aName = NS_LITERAL_CSTRING(""));
      53             : 
      54             :   // Initialize this as a wrapper for the current PRThread.
      55             :   nsresult InitCurrentThread();
      56             : 
      57             :   // The PRThread corresponding to this thread.
      58         134 :   PRThread* GetPRThread()
      59             :   {
      60         134 :     return mThread;
      61             :   }
      62             : 
      63             :   // If this flag is true, then the nsThread was created using
      64             :   // nsIThreadManager::NewThread.
      65           0 :   bool ShutdownRequired()
      66             :   {
      67           0 :     return mShutdownRequired;
      68             :   }
      69             : 
      70             :   // Clear the observer list.
      71           1 :   void ClearObservers()
      72             :   {
      73           1 :     mEventObservers.Clear();
      74           1 :   }
      75             : 
      76             :   void
      77             :   SetScriptObserver(mozilla::CycleCollectedJSContext* aScriptObserver);
      78             : 
      79             :   uint32_t
      80             :   RecursionDepth() const;
      81             : 
      82             :   void ShutdownComplete(NotNull<struct nsThreadShutdownContext*> aContext);
      83             : 
      84             :   void WaitForAllAsynchronousShutdowns();
      85             : 
      86             : #ifdef MOZ_CRASHREPORTER
      87             :   enum class ShouldSaveMemoryReport
      88             :   {
      89             :     kMaybeReport,
      90             :     kForceReport
      91             :   };
      92             : 
      93             :   static bool SaveMemoryReportNearOOM(ShouldSaveMemoryReport aShouldSave);
      94             : #endif
      95             : 
      96             :   static const char* sMainThreadRunnableName;
      97             : 
      98             : private:
      99             :   void DoMainThreadSpecificProcessing(bool aReallyWait);
     100             : 
     101             :   // Returns a null TimeStamp if we're not in the idle period.
     102             :   mozilla::TimeStamp GetIdleDeadline();
     103             :   void GetIdleEvent(nsIRunnable** aEvent, mozilla::MutexAutoLock& aProofOfLock);
     104             :   void GetEvent(bool aWait, nsIRunnable** aEvent,
     105             :                 unsigned short* aPriority,
     106             :                 mozilla::MutexAutoLock& aProofOfLock);
     107             : 
     108             : protected:
     109             :   class nsChainedEventQueue;
     110             : 
     111             :   class nsNestedEventTarget;
     112             :   friend class nsNestedEventTarget;
     113             : 
     114             :   friend class nsThreadShutdownEvent;
     115             : 
     116             :   virtual ~nsThread();
     117             : 
     118        2988 :   bool ShuttingDown()
     119             :   {
     120        2988 :     return mShutdownContext != nullptr;
     121             :   }
     122             : 
     123             :   static void ThreadFunc(void* aArg);
     124             : 
     125             :   // Helper
     126             :   already_AddRefed<nsIThreadObserver> GetObserver()
     127             :   {
     128             :     nsIThreadObserver* obs;
     129             :     nsThread::GetObserver(&obs);
     130             :     return already_AddRefed<nsIThreadObserver>(obs);
     131             :   }
     132             : 
     133             :   // Wrappers for event queue methods:
     134             :   nsresult PutEvent(nsIRunnable* aEvent, nsNestedEventTarget* aTarget);
     135             :   nsresult PutEvent(already_AddRefed<nsIRunnable> aEvent,
     136             :                     nsNestedEventTarget* aTarget);
     137             : 
     138             :   nsresult DispatchInternal(already_AddRefed<nsIRunnable> aEvent,
     139             :                             uint32_t aFlags, nsNestedEventTarget* aTarget);
     140             : 
     141             :   struct nsThreadShutdownContext* ShutdownInternal(bool aSync);
     142             : 
     143             :   // Wrapper for nsEventQueue that supports chaining.
     144          14 :   class nsChainedEventQueue
     145             :   {
     146             :   public:
     147          83 :     explicit nsChainedEventQueue(mozilla::Mutex& aLock)
     148          83 :       : mNext(nullptr)
     149             :       , mEventsAvailable(aLock, "[nsChainedEventQueue.mEventsAvailable]")
     150          83 :       , mProcessSecondaryQueueRunnable(false)
     151             :     {
     152             :       mNormalQueue =
     153         166 :         mozilla::MakeUnique<nsEventQueue>(mEventsAvailable,
     154          83 :                                           nsEventQueue::eSharedCondVarQueue);
     155             :       // Both queues need to use the same CondVar!
     156             :       mSecondaryQueue =
     157         166 :         mozilla::MakeUnique<nsEventQueue>(mEventsAvailable,
     158          83 :                                           nsEventQueue::eSharedCondVarQueue);
     159          83 :     }
     160             : 
     161             :     bool GetEvent(bool aMayWait, nsIRunnable** aEvent,
     162             :                   unsigned short* aPriority,
     163             :                   mozilla::MutexAutoLock& aProofOfLock);
     164             : 
     165          56 :     void PutEvent(nsIRunnable* aEvent, mozilla::MutexAutoLock& aProofOfLock)
     166             :     {
     167         112 :       RefPtr<nsIRunnable> event(aEvent);
     168          56 :       PutEvent(event.forget(), aProofOfLock);
     169          56 :     }
     170             : 
     171        1623 :     void PutEvent(already_AddRefed<nsIRunnable> aEvent,
     172             :                   mozilla::MutexAutoLock& aProofOfLock)
     173             :     {
     174        3246 :       RefPtr<nsIRunnable> event(aEvent);
     175             :       nsCOMPtr<nsIRunnablePriority> runnablePrio =
     176        3246 :         do_QueryInterface(event);
     177        1623 :       uint32_t prio = nsIRunnablePriority::PRIORITY_NORMAL;
     178        1623 :       if (runnablePrio) {
     179         318 :         runnablePrio->GetPriority(&prio);
     180             :       }
     181        1623 :       MOZ_ASSERT(prio == nsIRunnablePriority::PRIORITY_NORMAL ||
     182             :                  prio == nsIRunnablePriority::PRIORITY_HIGH);
     183        1623 :       if (prio == nsIRunnablePriority::PRIORITY_NORMAL) {
     184        1549 :         mNormalQueue->PutEvent(event.forget(), aProofOfLock);
     185             :       } else {
     186          74 :         mSecondaryQueue->PutEvent(event.forget(), aProofOfLock);
     187             :       }
     188        1623 :     }
     189             : 
     190        1710 :     bool HasPendingEvent(mozilla::MutexAutoLock& aProofOfLock)
     191             :     {
     192        2012 :       return mNormalQueue->HasPendingEvent(aProofOfLock) ||
     193        2012 :              mSecondaryQueue->HasPendingEvent(aProofOfLock);
     194             :     }
     195             : 
     196             :     nsChainedEventQueue* mNext;
     197             :     RefPtr<nsNestedEventTarget> mEventTarget;
     198             : 
     199             :   private:
     200             :     mozilla::CondVar mEventsAvailable;
     201             :     mozilla::UniquePtr<nsEventQueue> mNormalQueue;
     202             :     mozilla::UniquePtr<nsEventQueue> mSecondaryQueue;
     203             : 
     204             :     // Try to process one high priority runnable after each normal
     205             :     // priority runnable. This gives the processing model HTML spec has for
     206             :     // 'Update the rendering' in the case only vsync messages are in the
     207             :     // secondary queue and prevents starving the normal queue.
     208             :     bool mProcessSecondaryQueueRunnable;
     209             :   };
     210             : 
     211             :   class nsNestedEventTarget final : public nsIEventTarget
     212             :   {
     213             :   public:
     214             :     NS_DECL_THREADSAFE_ISUPPORTS
     215             :     NS_DECL_NSIEVENTTARGET_FULL
     216             : 
     217          17 :     nsNestedEventTarget(NotNull<nsThread*> aThread,
     218             :                         NotNull<nsChainedEventQueue*> aQueue)
     219          17 :       : mThread(aThread)
     220          17 :       , mQueue(aQueue)
     221             : 
     222             : 
     223             : 
     224             :     {
     225          17 :     }
     226             : 
     227             :     NotNull<RefPtr<nsThread>> mThread;
     228             : 
     229             :     // This is protected by mThread->mLock.
     230             :     nsChainedEventQueue* mQueue;
     231             : 
     232             :   private:
     233          13 :     ~nsNestedEventTarget()
     234          13 :     {
     235          13 :     }
     236             :   };
     237             : 
     238             :   // This lock protects access to mObserver, mEvents, mIdleEvents,
     239             :   // mIdlePeriod and mEventsAreDoomed.  All of those fields are only
     240             :   // modified on the thread itself (never from another thread).  This
     241             :   // means that we can avoid holding the lock while using mObserver
     242             :   // and mEvents on the thread itself.  When calling PutEvent on
     243             :   // mEvents, we have to hold the lock to synchronize with
     244             :   // PopEventQueue.
     245             :   mozilla::Mutex mLock;
     246             : 
     247             :   nsCOMPtr<nsIThreadObserver> mObserver;
     248             :   mozilla::CycleCollectedJSContext* mScriptObserver;
     249             : 
     250             :   // Only accessed on the target thread.
     251             :   nsAutoTObserverArray<NotNull<nsCOMPtr<nsIThreadObserver>>, 2> mEventObservers;
     252             : 
     253             :   NotNull<nsChainedEventQueue*> mEvents;  // never null
     254             :   nsChainedEventQueue mEventsRoot;
     255             : 
     256             :   // mIdlePeriod keeps track of the current idle period. If at any
     257             :   // time the main event queue is empty, calling
     258             :   // mIdlePeriod->GetIdlePeriodHint() will give an estimate of when
     259             :   // the current idle period will end.
     260             :   nsCOMPtr<nsIIdlePeriod> mIdlePeriod;
     261             :   mozilla::CondVar mIdleEventsAvailable;
     262             :   nsEventQueue mIdleEvents;
     263             : 
     264             :   int32_t   mPriority;
     265             :   PRThread* mThread;
     266             :   uint32_t  mNestedEventLoopDepth;
     267             :   uint32_t  mStackSize;
     268             : 
     269             :   // The shutdown context for ourselves.
     270             :   struct nsThreadShutdownContext* mShutdownContext;
     271             :   // The shutdown contexts for any other threads we've asked to shut down.
     272             :   nsTArray<nsAutoPtr<struct nsThreadShutdownContext>> mRequestedShutdownContexts;
     273             : 
     274             :   bool mShutdownRequired;
     275             :   // Set to true when events posted to this thread will never run.
     276             :   bool mEventsAreDoomed;
     277             :   MainThreadFlag mIsMainThread;
     278             : 
     279             :   // The time when we last ran an unlabeled runnable (one not associated with a
     280             :   // SchedulerGroup).
     281             :   mozilla::TimeStamp mLastUnlabeledRunnable;
     282             : 
     283             :   // Set to true if this thread creates a JSRuntime.
     284             :   bool mCanInvokeJS;
     285             :   // Set to true if HasPendingEvents() has been called and returned true because
     286             :   // of a pending idle event.  This is used to remember to return that idle
     287             :   // event from GetIdleEvent() to ensure that HasPendingEvents() never lies.
     288             :   bool mHasPendingEventsPromisedIdleEvent;
     289             : 
     290             : #ifndef RELEASE_OR_BETA
     291             :   mozilla::TimeStamp mNextIdleDeadline;
     292             : #endif
     293             : };
     294             : 
     295             : #if defined(XP_UNIX) && !defined(ANDROID) && !defined(DEBUG) && HAVE_UALARM \
     296             :   && defined(_GNU_SOURCE)
     297             : # define MOZ_CANARY
     298             : 
     299             : extern int sCanaryOutputFD;
     300             : #endif
     301             : 
     302             : #endif  // nsThread_h__

Generated by: LCOV version 1.13