Bug 1355746 - Part 1. Rename CollectRunner to IdleTaskRunner and move to xpcom/threads/IdleTaskRunner.h/cpp draft
authorHenry Chang <hchang@mozilla.com>
Thu, 15 Jun 2017 14:47:56 +0800
changeset 601762 27754367ed8baabcce8f920fbf5be18a19fd8227
parent 601761 61b71b3d8354994a136c785a25a205433cadcf1c
child 601763 7a82e81c8fac78c9482b7585b73a146bce6f1665
push id66200
push userhchang@mozilla.com
push dateThu, 29 Jun 2017 03:53:43 +0000
bugs1355746
milestone56.0a1
Bug 1355746 - Part 1. Rename CollectRunner to IdleTaskRunner and move to xpcom/threads/IdleTaskRunner.h/cpp Nothing is changed in this patch except for renaming and code move around. The strategy is to have the final file setup in this patch without any detail change. The actual code change will be in the next patch so that we can focus on reviewing the diff in the next patch regarding IdleTaskRunner. MozReview-Commit-ID: 4Bul9mZ7z1n
dom/base/nsJSEnvironment.cpp
xpcom/threads/IdleTaskRunner.cpp
xpcom/threads/IdleTaskRunner.h
xpcom/threads/moz.build
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -83,16 +83,17 @@
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/asmjscache/AsmJSCache.h"
 #include "mozilla/dom/CanvasRenderingContext2DBinding.h"
 #include "mozilla/ContentEvents.h"
 
 #include "nsCycleCollectionNoteRootCallback.h"
 #include "GeckoProfiler.h"
+#include "mozilla/IdleTaskRunner.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 const size_t gStackSize = 8192;
 
 // Thank you Microsoft!
 #ifdef CompareString
@@ -116,17 +117,17 @@ const size_t gStackSize = 8192;
 
 // The amount of time we wait between a request to CC (after GC ran)
 // and doing the actual CC.
 #define NS_CC_DELAY                 6000 // ms
 
 #define NS_CC_SKIPPABLE_DELAY       250 // ms
 
 // ForgetSkippable is usually fast, so we can use small budgets.
-// This isn't a real budget but a hint to CollectorRunner whether there
+// This isn't a real budget but a hint to IdleTaskRunner whether there
 // is enough time to call ForgetSkippable.
 static const int64_t kForgetSkippableSliceDuration = 2;
 
 // Maximum amount of time that should elapse between incremental CC slices
 static const int64_t kICCIntersliceDelay = 64; // ms
 
 // Time budget for an incremental CC slice when using timer to run it.
 static const int64_t kICCSliceBudget = 3; // ms
@@ -145,26 +146,24 @@ static const uint32_t kMaxICCDuration = 
 #define NS_MAX_CC_LOCKEDOUT_TIME    (30 * PR_USEC_PER_SEC) // 30 seconds
 
 // Trigger a CC if the purple buffer exceeds this size when we check it.
 #define NS_CC_PURPLE_LIMIT          200
 
 // Large value used to specify that a script should run essentially forever
 #define NS_UNLIMITED_SCRIPT_RUNTIME (0x40000000LL << 32)
 
-class CollectorRunner;
-
 // if you add statics here, add them to the list in StartupJSEnvironment
 
 static nsITimer *sGCTimer;
 static nsITimer *sShrinkingGCTimer;
-static StaticRefPtr<CollectorRunner> sCCRunner;
-static StaticRefPtr<CollectorRunner> sICCRunner;
+static StaticRefPtr<IdleTaskRunner> sCCRunner;
+static StaticRefPtr<IdleTaskRunner> sICCRunner;
 static nsITimer *sFullGCTimer;
-static StaticRefPtr<CollectorRunner> sInterSliceGCRunner;
+static StaticRefPtr<IdleTaskRunner> sInterSliceGCRunner;
 
 static TimeStamp sLastCCEndTime;
 
 static bool sCCLockedOut;
 static PRTime sCCLockedOutTime;
 
 static JS::GCSliceCallback sPrevGCSliceCallback;
 
@@ -224,193 +223,16 @@ static bool sIsCompactingOnUserInactive 
 
 // In testing, we call RunNextCollectorTimer() to ensure that the collectors are run more
 // aggressively than they would be in regular browsing. sExpensiveCollectorPokes keeps
 // us from triggering expensive full collections too frequently.
 static int32_t sExpensiveCollectorPokes = 0;
 static const int32_t kPokesBetweenExpensiveCollectorTriggers = 5;
 
 static TimeDuration sGCUnnotifiedTotalTime;
-
-// Return true if some meaningful work was done.
-typedef bool (*CollectorRunnerCallback) (TimeStamp aDeadline, void* aData);
-
-// Repeating callback runner for CC and GC.
-class CollectorRunner final : public IdleRunnable
-{
-public:
-  static already_AddRefed<CollectorRunner>
-  Create(CollectorRunnerCallback aCallback, uint32_t aDelay,
-         int64_t aBudget, bool aRepeating, void* aData = nullptr)
-  {
-    if (sShuttingDown) {
-      return nullptr;
-    }
-
-    RefPtr<CollectorRunner> runner =
-      new CollectorRunner(aCallback, aDelay, aBudget, aRepeating, aData);
-    runner->Schedule(false); // Initial scheduling shouldn't use idle dispatch.
-    return runner.forget();
-  }
-
-  NS_IMETHOD Run() override
-  {
-    if (!mCallback) {
-      return NS_OK;
-    }
-
-    // Deadline is null when called from timer.
-    bool deadLineWasNull = mDeadline.IsNull();
-    bool didRun = false;
-    if (deadLineWasNull || ((TimeStamp::Now() + mBudget) < mDeadline)) {
-      CancelTimer();
-      didRun = mCallback(mDeadline, mData);
-    }
-
-    if (mCallback && (mRepeating || !didRun)) {
-      // If we didn't do meaningful work, don't schedule using immediate
-      // idle dispatch, since that could lead to a loop until the idle
-      // period ends.
-      Schedule(didRun);
-    }
-
-    return NS_OK;
-  }
-
-  static void
-  TimedOut(nsITimer* aTimer, void* aClosure)
-  {
-    RefPtr<CollectorRunner> runnable = static_cast<CollectorRunner*>(aClosure);
-    runnable->Run();
-  }
-
-  void SetDeadline(mozilla::TimeStamp aDeadline) override
-  {
-    mDeadline = aDeadline;
-  };
-
-  void SetTimer(uint32_t aDelay, nsIEventTarget* aTarget) override
-  {
-    if (mTimerActive) {
-      return;
-    }
-
-    mTarget = aTarget;
-    if (!mTimer) {
-      mTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
-    } else {
-      mTimer->Cancel();
-    }
-
-    if (mTimer) {
-      mTimer->SetTarget(mTarget);
-      mTimer->InitWithFuncCallback(TimedOut, this, aDelay,
-                                   nsITimer::TYPE_ONE_SHOT);
-      mTimerActive = true;
-    }
-  }
-
-  nsresult Cancel() override
-  {
-    CancelTimer();
-    mTimer = nullptr;
-    mScheduleTimer = nullptr;
-    mCallback = nullptr;
-    return NS_OK;
-  }
-
-  static void
-  ScheduleTimedOut(nsITimer* aTimer, void* aClosure)
-  {
-    RefPtr<CollectorRunner> runnable = static_cast<CollectorRunner*>(aClosure);
-    runnable->Schedule(true);
-  }
-
-  void Schedule(bool aAllowIdleDispatch)
-  {
-    if (!mCallback) {
-      return;
-    }
-
-    if (sShuttingDown) {
-      Cancel();
-      return;
-    }
-
-    mDeadline = TimeStamp();
-    TimeStamp now = TimeStamp::Now();
-    TimeStamp hint = nsRefreshDriver::GetIdleDeadlineHint(now);
-    if (hint != now) {
-      // RefreshDriver is ticking, let it schedule the idle dispatch.
-      nsRefreshDriver::DispatchIdleRunnableAfterTick(this, mDelay);
-      // Ensure we get called at some point, even if RefreshDriver is stopped.
-      SetTimer(mDelay, mTarget);
-    } else {
-      // RefreshDriver doesn't seem to be running.
-      if (aAllowIdleDispatch) {
-        nsCOMPtr<nsIRunnable> runnable = this;
-        NS_IdleDispatchToCurrentThread(runnable.forget(), mDelay);
-        SetTimer(mDelay, mTarget);
-      } else {
-        if (!mScheduleTimer) {
-          mScheduleTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
-          if (!mScheduleTimer) {
-            return;
-          }
-        } else {
-          mScheduleTimer->Cancel();
-        }
-
-        // We weren't allowed to do idle dispatch immediately, do it after a
-        // short timeout.
-        mScheduleTimer->InitWithFuncCallback(ScheduleTimedOut, this, 16,
-                                             nsITimer::TYPE_ONE_SHOT_LOW_PRIORITY);
-      }
-    }
-  }
-
-private:
-  explicit CollectorRunner(CollectorRunnerCallback aCallback,
-                           uint32_t aDelay, int64_t aBudget,
-                           bool aRepeating, void* aData)
-    : mCallback(aCallback), mDelay(aDelay)
-    , mBudget(TimeDuration::FromMilliseconds(aBudget))
-    , mRepeating(aRepeating), mTimerActive(false), mData(aData)
-  {
-  }
-
-  ~CollectorRunner()
-  {
-    CancelTimer();
-  }
-
-  void CancelTimer()
-  {
-    nsRefreshDriver::CancelIdleRunnable(this);
-    if (mTimer) {
-      mTimer->Cancel();
-    }
-    if (mScheduleTimer) {
-      mScheduleTimer->Cancel();
-    }
-    mTimerActive = false;
-  }
-
-  nsCOMPtr<nsITimer> mTimer;
-  nsCOMPtr<nsITimer> mScheduleTimer;
-  nsCOMPtr<nsIEventTarget> mTarget;
-  CollectorRunnerCallback mCallback;
-  uint32_t mDelay;
-  TimeStamp mDeadline;
-  TimeDuration mBudget;
-  bool mRepeating;
-  bool mTimerActive;
-  void* mData;
-};
-
 static const char*
 ProcessNameForCollectorLog()
 {
   return XRE_GetProcessType() == GeckoProcessType_Default ?
     "default" : "content";
 }
 
 namespace xpc {
new file mode 100644
--- /dev/null
+++ b/xpcom/threads/IdleTaskRunner.cpp
@@ -0,0 +1,172 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "IdleTaskRunner.h"
+#include "nsRefreshDriver.h"
+
+namespace mozilla {
+
+already_AddRefed<IdleTaskRunner>
+IdleTaskRunner::Create(IdleTaskRunnerCallback aCallback, uint32_t aDelay,
+                       int64_t aBudget, bool aRepeating, void* aData)
+{
+  if (sShuttingDown) {
+    return nullptr;
+  }
+
+  RefPtr<IdleTaskRunner> runner =
+    new IdleTaskRunner(aCallback, aDelay, aBudget, aRepeating, aData);
+  runner->Schedule(false); // Initial scheduling shouldn't use idle dispatch.
+  return runner.forget();
+}
+
+IdleTaskRunner::IdleTaskRunner(IdleTaskRunnerCallback aCallback,
+                               uint32_t aDelay, int64_t aBudget,
+                               bool aRepeating, void* aData)
+  : mCallback(aCallback), mDelay(aDelay)
+  , mBudget(TimeDuration::FromMilliseconds(aBudget))
+  , mRepeating(aRepeating), mTimerActive(false), mData(aData)
+{
+}
+
+NS_IMETHODIMP
+IdleTaskRunner::Run()
+{
+  if (!mCallback) {
+    return NS_OK;
+  }
+
+  // Deadline is null when called from timer.
+  bool deadLineWasNull = mDeadline.IsNull();
+  bool didRun = false;
+  if (deadLineWasNull || ((TimeStamp::Now() + mBudget) < mDeadline)) {
+    CancelTimer();
+    didRun = mCallback(mDeadline, mData);
+  }
+
+  if (mCallback && (mRepeating || !didRun)) {
+    // If we didn't do meaningful work, don't schedule using immediate
+    // idle dispatch, since that could lead to a loop until the idle
+    // period ends.
+    Schedule(didRun);
+  }
+
+  return NS_OK;
+}
+
+static void
+TimedOut(nsITimer* aTimer, void* aClosure)
+{
+  RefPtr<IdleTaskRunner> runnable = static_cast<IdleTaskRunner*>(aClosure);
+  runnable->Run();
+}
+
+void
+IdleTaskRunner::SetDeadline(mozilla::TimeStamp aDeadline)
+{
+  mDeadline = aDeadline;
+};
+
+void IdleTaskRunner::SetTimer(uint32_t aDelay, nsIEventTarget* aTarget)
+{
+  if (mTimerActive) {
+    return;
+  }
+  mTarget = aTarget;
+  if (!mTimer) {
+    mTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
+  } else {
+    mTimer->Cancel();
+  }
+
+  if (mTimer) {
+    mTimer->SetTarget(mTarget);
+    mTimer->InitWithFuncCallback(TimedOut, this, aDelay,
+                                 nsITimer::TYPE_ONE_SHOT);
+    mTimerActive = true;
+  }
+}
+
+nsresult
+IdleTaskRunner::Cancel()
+{
+  CancelTimer();
+  mTimer = nullptr;
+  mScheduleTimer = nullptr;
+  mCallback = nullptr;
+  return NS_OK;
+}
+
+static void
+ScheduleTimedOut(nsITimer* aTimer, void* aClosure)
+{
+  RefPtr<IdleTaskRunner> runnable = static_cast<IdleTaskRunner*>(aClosure);
+  runnable->Schedule(true);
+}
+
+void
+IdleTaskRunner::Schedule(bool aAllowIdleDispatch)
+{
+  if (!mCallback) {
+    return;
+  }
+
+  if (sShuttingDown) {
+    Cancel();
+    return;
+  }
+
+  mDeadline = TimeStamp();
+  TimeStamp now = TimeStamp::Now();
+  TimeStamp hint = nsRefreshDriver::GetIdleDeadlineHint(now);
+  if (hint != now) {
+    // RefreshDriver is ticking, let it schedule the idle dispatch.
+    nsRefreshDriver::DispatchIdleRunnableAfterTick(this, mDelay);
+    // Ensure we get called at some point, even if RefreshDriver is stopped.
+    SetTimer(mDelay, mTarget);
+  } else {
+    // RefreshDriver doesn't seem to be running.
+    if (aAllowIdleDispatch) {
+      nsCOMPtr<nsIRunnable> runnable = this;
+      NS_IdleDispatchToCurrentThread(runnable.forget(), mDelay);
+      SetTimer(mDelay, mTarget);
+    } else {
+      if (!mScheduleTimer) {
+        mScheduleTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
+        if (!mScheduleTimer) {
+          return;
+        }
+      } else {
+        mScheduleTimer->Cancel();
+      }
+
+      // We weren't allowed to do idle dispatch immediately, do it after a
+      // short timeout.
+      mScheduleTimer->InitWithFuncCallback(ScheduleTimedOut, this, 16,
+                                           nsITimer::TYPE_ONE_SHOT_LOW_PRIORITY);
+    }
+  }
+}
+
+IdleTaskRunner::~IdleTaskRunner()
+{
+  CancelTimer();
+}
+
+void
+IdleTaskRunner::CancelTimer()
+{
+  nsRefreshDriver::CancelIdleRunnable(this);
+  if (mTimer) {
+    mTimer->Cancel();
+  }
+  if (mScheduleTimer) {
+    mScheduleTimer->Cancel();
+  }
+  mTimerActive = false;
+}
+
+} // end of namespace mozilla
new file mode 100644
--- /dev/null
+++ b/xpcom/threads/IdleTaskRunner.h
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef IdleTaskRunner_h
+#define IdleTaskRunner_h
+
+#include "nsThreadUtils.h"
+
+namespace mozilla {
+
+// Return true if some meaningful work was done.
+typedef bool (*IdleTaskRunnerCallback) (TimeStamp aDeadline, void* aData);
+
+// Repeating callback runner for CC and GC.
+class IdleTaskRunner final : public IdleRunnable
+{
+public:
+  static already_AddRefed<IdleTaskRunner>
+  Create(IdleTaskRunnerCallback aCallback, uint32_t aDelay,
+         int64_t aBudget, bool aRepeating, void* aData = nullptr);
+
+  NS_IMETHOD Run() override;
+
+  void SetDeadline(mozilla::TimeStamp aDeadline) override;
+  void SetTimer(uint32_t aDelay, nsIEventTarget* aTarget) override;
+
+  nsresult Cancel() override;
+  void Schedule(bool aAllowIdleDispatch);
+
+private:
+  explicit IdleTaskRunner(IdleTaskRunnerCallback aCallback,
+                          uint32_t aDelay, int64_t aBudget,
+                          bool aRepeating, void* aData);
+  ~IdleTaskRunner();
+  void CancelTimer();
+
+  nsCOMPtr<nsITimer> mTimer;
+  nsCOMPtr<nsITimer> mScheduleTimer;
+  nsCOMPtr<nsIEventTarget> mTarget;
+  IdleTaskRunnerCallback mCallback;
+  uint32_t mDelay;
+  TimeStamp mDeadline;
+  TimeDuration mBudget;
+  bool mRepeating;
+  bool mTimerActive;
+  void* mData;
+};
+
+} // end of unnamed namespace.
+
+#endif
--- a/xpcom/threads/moz.build
+++ b/xpcom/threads/moz.build
@@ -37,16 +37,17 @@ EXPORTS += [
 EXPORTS.mozilla += [
     'AbstractThread.h',
     'BackgroundHangMonitor.h',
     'BlockingResourceBase.h',
     'CondVar.h',
     'DeadlockDetector.h',
     'HangAnnotations.h',
     'HangMonitor.h',
+    'IdleTaskRunner.h',
     'LazyIdleThread.h',
     'MainThreadIdlePeriod.h',
     'Monitor.h',
     'MozPromise.h',
     'Mutex.h',
     'ReentrantMonitor.h',
     'RWLock.h',
     'SchedulerGroup.h',
@@ -62,16 +63,17 @@ EXPORTS.mozilla += [
 ]
 
 UNIFIED_SOURCES += [
     'AbstractThread.cpp',
     'BackgroundHangMonitor.cpp',
     'BlockingResourceBase.cpp',
     'HangAnnotations.cpp',
     'HangMonitor.cpp',
+    'IdleTaskRunner.cpp',
     'LazyIdleThread.cpp',
     'MainThreadIdlePeriod.cpp',
     'nsEnvironment.cpp',
     'nsEventQueue.cpp',
     'nsMemoryPressure.cpp',
     'nsProcessCommon.cpp',
     'nsProxyRelease.cpp',
     'nsThread.cpp',