Bug 1323337 - Refactor two methods looping over timeouts from TimeoutManager into Timeouts; r=bkelly
authorEhsan Akhgari <ehsan@mozilla.com>
Tue, 13 Dec 2016 19:06:21 -0500
changeset 325897 65d60084b5ebe1bafe686a883d76b87759e9db93
parent 325896 4d62ef0ed85ef48a05a45347318d75efac402ef5
child 325898 756b4447cae3fa1877d1252526384988d9e570f2
push id84826
push usereakhgari@mozilla.com
push dateWed, 14 Dec 2016 21:02:27 +0000
treeherdermozilla-inbound@65d60084b5eb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbkelly
bugs1323337
milestone53.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1323337 - Refactor two methods looping over timeouts from TimeoutManager into Timeouts; r=bkelly With this patch, all of the methods which loop over the timeouts are refactored in preparation for splitting the list of timeouts into a tracking and a normal list.
dom/base/TimeoutManager.cpp
dom/base/TimeoutManager.h
--- a/dom/base/TimeoutManager.cpp
+++ b/dom/base/TimeoutManager.cpp
@@ -6,16 +6,17 @@
 
 #include "TimeoutManager.h"
 #include "nsGlobalWindow.h"
 #include "mozilla/ThrottledEventQueue.h"
 #include "mozilla/TimeStamp.h"
 #include "nsITimeoutHandler.h"
 #include "mozilla/dom/TabGroup.h"
 
+using namespace mozilla;
 using namespace mozilla::dom;
 
 static int32_t              gRunningTimeoutDepth       = 0;
 
 // The default shortest interval/timeout we permit
 #define DEFAULT_MIN_TIMEOUT_VALUE 4 // 4ms
 #define DEFAULT_MIN_BACKGROUND_TIMEOUT_VALUE 1000 // 1000ms
 static int32_t gMinTimeoutValue;
@@ -222,17 +223,18 @@ TimeoutManager::SetTimeout(nsITimeoutHan
     // This is checking |interval|, not realInterval, on purpose,
     // because our lower bound for |realInterval| could be pretty high
     // in some cases.
     if (interval <= delay) {
       timeout->mPopupState = mWindow.GetPopupControlState();
     }
   }
 
-  InsertTimeoutIntoList(timeout);
+  mTimeouts.Insert(timeout, mWindow.IsFrozen() ? Timeouts::SortBy::TimeRemaining
+                                               : Timeouts::SortBy::TimeWhen);
 
   timeout->mTimeoutId = GetTimeoutId(aReason);
   *aReturn = timeout->mTimeoutId;
 
   return NS_OK;
 }
 
 void
@@ -415,17 +417,18 @@ TimeoutManager::RunTimeout(Timeout* aTim
     // we need to reset the pointer to the following timeout.
     nextTimeout = timeout->getNext();
 
     timeout->remove();
 
     if (needsReinsertion) {
       // Insert interval timeout onto list sorted in deadline order.
       // AddRefs timeout.
-      InsertTimeoutIntoList(timeout);
+      mTimeouts.Insert(timeout, mWindow.IsFrozen() ? Timeouts::SortBy::TimeRemaining
+                                                   : Timeouts::SortBy::TimeWhen);
     }
 
     // Release the timeout struct since it's possibly out of the list
     timeout->Release();
   }
 
   // Take the dummy timeout off the head of the list
   dummy_timeout->remove();
@@ -624,27 +627,42 @@ nsresult
 TimeoutManager::ResetTimersForThrottleReduction(int32_t aPreviousThrottleDelayMS)
 {
   MOZ_ASSERT(aPreviousThrottleDelayMS > 0);
 
   if (mWindow.IsFrozen() || mWindow.IsSuspended()) {
     return NS_OK;
   }
 
+  Timeouts::SortBy sortBy = mWindow.IsFrozen() ? Timeouts::SortBy::TimeRemaining
+                                               : Timeouts::SortBy::TimeWhen;
+
+  return mTimeouts.ResetTimersForThrottleReduction(aPreviousThrottleDelayMS,
+                                                   DOMMinTimeoutValue(),
+                                                   sortBy,
+                                                   mWindow.GetThrottledEventQueue());
+}
+
+nsresult
+TimeoutManager::Timeouts::ResetTimersForThrottleReduction(int32_t aPreviousThrottleDelayMS,
+                                                          int32_t aMinTimeoutValueMS,
+                                                          SortBy aSortBy,
+                                                          ThrottledEventQueue* aQueue)
+{
   TimeStamp now = TimeStamp::Now();
 
   // If insertion point is non-null, we're in the middle of firing timers and
   // the timers we're planning to fire all come before insertion point;
   // insertion point itself is a dummy timeout with an mWhen that may be
   // semi-bogus.  In that case, we don't need to do anything with insertion
   // point or anything before it, so should start at the timer after insertion
   // point, if there is one.
   // Otherwise, start at the beginning of the list.
-  for (Timeout* timeout = mTimeouts.InsertionPoint() ?
-         mTimeouts.InsertionPoint()->getNext() : mTimeouts.GetFirst();
+  for (Timeout* timeout = InsertionPoint() ?
+         InsertionPoint()->getNext() : GetFirst();
        timeout; ) {
     // It's important that this check be <= so that we guarantee that
     // taking std::max with |now| won't make a quantity equal to
     // timeout->mWhen below.
     if (timeout->mWhen <= now) {
       timeout = timeout->getNext();
       continue;
     }
@@ -657,17 +675,17 @@ TimeoutManager::ResetTimersForThrottleRe
       break;
     }
 
     // We reduced our throttled delay. Re-init the timer appropriately.
     // Compute the interval the timer should have had if it had not been set in a
     // background window
     TimeDuration interval =
       TimeDuration::FromMilliseconds(std::max(timeout->mInterval,
-                                            uint32_t(DOMMinTimeoutValue())));
+                                            uint32_t(aMinTimeoutValueMS)));
     uint32_t oldIntervalMillisecs = 0;
     timeout->mTimer->GetDelay(&oldIntervalMillisecs);
     TimeDuration oldInterval = TimeDuration::FromMilliseconds(oldIntervalMillisecs);
     if (oldInterval > interval) {
       // unclamp
       TimeStamp firingTime =
         std::max(timeout->mWhen - oldInterval + interval, now);
 
@@ -685,25 +703,24 @@ TimeoutManager::ResetTimersForThrottleRe
       Timeout* nextTimeout = timeout->getNext();
 
       // It is safe to remove and re-insert because mWhen is now
       // strictly smaller than it used to be, so we know we'll insert
       // |timeout| before nextTimeout.
       NS_ASSERTION(!nextTimeout ||
                    timeout->mWhen < nextTimeout->mWhen, "How did that happen?");
       timeout->remove();
-      // InsertTimeoutIntoList will addref |timeout| and reset
-      // mFiringDepth.  Make sure to undo that after calling it.
+      // Insert() will addref |timeout| and reset mFiringDepth.  Make sure to
+      // undo that after calling it.
       uint32_t firingDepth = timeout->mFiringDepth;
-      InsertTimeoutIntoList(timeout);
+      Insert(timeout, aSortBy);
       timeout->mFiringDepth = firingDepth;
       timeout->Release();
 
-      nsresult rv = timeout->InitTimer(mWindow.GetThrottledEventQueue(),
-                                       delay.ToMilliseconds());
+      nsresult rv = timeout->InitTimer(aQueue, delay.ToMilliseconds());
 
       if (NS_FAILED(rv)) {
         NS_WARNING("Error resetting non background timer for DOM timeout!");
         return rv;
       }
 
       timeout = nextTimeout;
     } else {
@@ -750,37 +767,37 @@ TimeoutManager::ClearAllTimeouts()
     mTimeouts.SetInsertionPoint(nullptr);
   }
 
   // Clear out our list
   mTimeouts.Clear();
 }
 
 void
-TimeoutManager::InsertTimeoutIntoList(Timeout* aTimeout)
+TimeoutManager::Timeouts::Insert(Timeout* aTimeout, SortBy aSortBy)
 {
   // Start at mLastTimeout and go backwards.  Don't go further than insertion
   // point, though.  This optimizes for the common case of insertion at the end.
   Timeout* prevSibling;
-  for (prevSibling = mTimeouts.GetLast();
-       prevSibling && prevSibling != mTimeouts.InsertionPoint() &&
+  for (prevSibling = GetLast();
+       prevSibling && prevSibling != InsertionPoint() &&
          // This condition needs to match the one in SetTimeoutOrInterval that
          // determines whether to set mWhen or mTimeRemaining.
-         (mWindow.IsFrozen() ?
+         (aSortBy == SortBy::TimeRemaining ?
           prevSibling->mTimeRemaining > aTimeout->mTimeRemaining :
           prevSibling->mWhen > aTimeout->mWhen);
        prevSibling = prevSibling->getPrevious()) {
     /* Do nothing; just searching */
   }
 
   // Now link in aTimeout after prevSibling.
   if (prevSibling) {
     prevSibling->setNext(aTimeout);
   } else {
-    mTimeouts.InsertFront(aTimeout);
+    InsertFront(aTimeout);
   }
 
   aTimeout->mFiringDepth = 0;
 
   // Increment the timeout's reference count since it's now held on to
   // by the list
   aTimeout->AddRef();
 }
--- a/dom/base/TimeoutManager.h
+++ b/dom/base/TimeoutManager.h
@@ -8,16 +8,19 @@
 #define mozilla_dom_TimeoutManager_h__
 
 #include "mozilla/dom/Timeout.h"
 
 class nsITimeoutHandler;
 class nsGlobalWindow;
 
 namespace mozilla {
+
+class ThrottledEventQueue;
+
 namespace dom {
 
 // This class manages the timeouts in a Window's setTimeout/setInterval pool.
 class TimeoutManager final
 {
 public:
   explicit TimeoutManager(nsGlobalWindow& aWindow);
   TimeoutManager(const TimeoutManager& rhs) = delete;
@@ -39,19 +42,16 @@ public:
 
   // The timeout implementation functions.
   void RunTimeout(mozilla::dom::Timeout* aTimeout);
   // Return true if |aTimeout| needs to be reinserted into the timeout list.
   bool RescheduleTimeout(mozilla::dom::Timeout* aTimeout, const TimeStamp& now,
                          bool aRunningPendingTimeouts);
 
   void ClearAllTimeouts();
-  // Insert aTimeout into the list, before all timeouts that would
-  // fire after it, but no earlier than mTimeoutInsertionPoint, if any.
-  void InsertTimeoutIntoList(mozilla::dom::Timeout* aTimeout);
   uint32_t GetTimeoutId(mozilla::dom::Timeout::Reason aReason);
 
   // Apply back pressure to the window if the TabGroup ThrottledEventQueue
   // exists and has too many runnables waiting to run.  For example, increase
   // the minimum timer delay, etc.
   void MaybeApplyBackPressure();
 
   // Check the current ThrottledEventQueue depth and update the back pressure
@@ -104,16 +104,29 @@ private:
 private:
   typedef mozilla::LinkedList<mozilla::dom::Timeout> TimeoutList;
   struct Timeouts {
     Timeouts()
       : mTimeoutInsertionPoint(nullptr)
     {
     }
 
+    // Insert aTimeout into the list, before all timeouts that would
+    // fire after it, but no earlier than mTimeoutInsertionPoint, if any.
+    enum class SortBy
+    {
+      TimeRemaining,
+      TimeWhen
+    };
+    void Insert(mozilla::dom::Timeout* aTimeout, SortBy aSortBy);
+    nsresult ResetTimersForThrottleReduction(int32_t aPreviousThrottleDelayMS,
+                                             int32_t aMinTimeoutValueMS,
+                                             SortBy aSortBy,
+                                             mozilla::ThrottledEventQueue* aQueue);
+
     const Timeout* GetFirst() const { return mTimeoutList.getFirst(); }
     Timeout* GetFirst() { return mTimeoutList.getFirst(); }
     const Timeout* GetLast() const { return mTimeoutList.getLast(); }
     Timeout* GetLast() { return mTimeoutList.getLast(); }
     bool IsEmpty() const { return mTimeoutList.isEmpty(); }
     void InsertFront(Timeout* aTimeout) { mTimeoutList.insertFront(aTimeout); }
     void Clear() { mTimeoutList.clear(); }