Bug 1355746 - Part 1. Rename CollectRunner to IdleTaskRunner and move to xpcom/threads/IdleTaskRunner.h/cpp draft
authorHenry Chang <hchang@mozilla.com>
Mon, 07 Aug 2017 13:50:47 +0800
changeset 642449 bc25b9fd84a85622dbe7db18cfc1c139b8df42c5
parent 642204 65507616792c990b1230888612dd7ffc13ed32b4
child 642450 89a3a01fb3f5d41d712c4b798890ecf06cec3a4c
push id72752
push userhchang@mozilla.com
push dateTue, 08 Aug 2017 08:47:58 +0000
bugs1355746
milestone57.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
@@ -81,16 +81,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
@@ -114,17 +115,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
@@ -143,26 +144,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;
 
@@ -220,203 +219,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
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-    // aTarget is always the main thread event target provided from
-    // NS_IdleDispatchToCurrentThread(). We ignore aTarget here to ensure that
-    // CollectorRunner a(ways run specifically on SystemGroup::EventTargetFor(
-    // TaskCategory::GarbageCollection) of the main thread.
-    SetTimerInternal(aDelay);
-  }
-
-  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.
-      SetTimerInternal(mDelay);
-    } else {
-      // RefreshDriver doesn't seem to be running.
-      if (aAllowIdleDispatch) {
-        nsCOMPtr<nsIRunnable> runnable = this;
-        SetTimerInternal(mDelay);
-        NS_IdleDispatchToCurrentThread(runnable.forget());
-      } else {
-        if (!mScheduleTimer) {
-          mScheduleTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
-          if (!mScheduleTimer) {
-            return;
-          }
-          mScheduleTimer->SetTarget(SystemGroup::EventTargetFor(TaskCategory::GarbageCollection));
-        } else {
-          mScheduleTimer->Cancel();
-        }
-
-        // We weren't allowed to do idle dispatch immediately, do it after a
-        // short timeout.
-        mScheduleTimer->InitWithNamedFuncCallback(ScheduleTimedOut, this, 16,
-                                                  nsITimer::TYPE_ONE_SHOT_LOW_PRIORITY,
-                                                  "CollectorRunner");
-      }
-    }
-  }
-
-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;
-  }
-
-  void SetTimerInternal(uint32_t aDelay)
-  {
-    if (mTimerActive) {
-      return;
-    }
-
-    if (!mTimer) {
-      mTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
-    } else {
-      mTimer->Cancel();
-    }
-
-    if (mTimer) {
-      mTimer->SetTarget(SystemGroup::EventTargetFor(TaskCategory::GarbageCollection));
-      mTimer->InitWithNamedFuncCallback(TimedOut, this, aDelay,
-                                        nsITimer::TYPE_ONE_SHOT,
-                                        "CollectorRunner");
-      mTimerActive = true;
-    }
-  }
-
-  nsCOMPtr<nsITimer> mTimer;
-  nsCOMPtr<nsITimer> mScheduleTimer;
-  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,187 @@
+/* -*- 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"
+#include "mozilla/SystemGroup.h"
+#include "nsComponentManagerUtils.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)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  // aTarget is always the main thread event target provided from
+  // NS_IdleDispatchToCurrentThread(). We ignore aTarget here to ensure that
+  // CollectorRunner always run specifically on SystemGroup::EventTargetFor(
+  // TaskCategory::GarbageCollection) of the main thread.
+  SetTimerInternal(aDelay);
+}
+
+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.
+    SetTimerInternal(mDelay);
+  } else {
+    // RefreshDriver doesn't seem to be running.
+    if (aAllowIdleDispatch) {
+      nsCOMPtr<nsIRunnable> runnable = this;
+      SetTimerInternal(mDelay);
+      NS_IdleDispatchToCurrentThread(runnable.forget());
+    } else {
+      if (!mScheduleTimer) {
+        mScheduleTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
+        if (!mScheduleTimer) {
+          return;
+        }
+      } else {
+        mScheduleTimer->Cancel();
+      }
+      mScheduleTimer->SetTarget(SystemGroup::EventTargetFor(TaskCategory::GarbageCollection));
+      // We weren't allowed to do idle dispatch immediately, do it after a
+      // short timeout.
+      mScheduleTimer->InitWithNamedFuncCallback(ScheduleTimedOut, this, 16,
+                                                nsITimer::TYPE_ONE_SHOT_LOW_PRIORITY,
+                                                "IdleTaskRunner");
+    }
+  }
+}
+
+IdleTaskRunner::~IdleTaskRunner()
+{
+  CancelTimer();
+}
+
+void
+IdleTaskRunner::CancelTimer()
+{
+  nsRefreshDriver::CancelIdleRunnable(this);
+  if (mTimer) {
+    mTimer->Cancel();
+  }
+  if (mScheduleTimer) {
+    mScheduleTimer->Cancel();
+  }
+  mTimerActive = false;
+}
+
+void 
+IdleTaskRunner::SetTimerInternal(uint32_t aDelay)
+{
+  if (mTimerActive) {
+    return;
+  }
+
+  if (!mTimer) {
+    mTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
+  } else {
+    mTimer->Cancel();
+  }
+
+  if (mTimer) {
+    mTimer->SetTarget(SystemGroup::EventTargetFor(TaskCategory::GarbageCollection));
+    mTimer->InitWithNamedFuncCallback(TimedOut, this, aDelay,
+                                      nsITimer::TYPE_ONE_SHOT,
+                                      "IdleTaskRunner");
+    mTimerActive = true;
+  }
+}
+
+} // end of namespace mozilla
new file mode 100644
--- /dev/null
+++ b/xpcom/threads/IdleTaskRunner.h
@@ -0,0 +1,55 @@
+/* -*- 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 "mozilla/TimeStamp.h"
+#include "mozilla/TaskCategory.h"
+#include "nsThreadUtils.h"
+
+namespace mozilla {
+
+// Return true if some meaningful work was done.
+typedef bool (*IdleTaskRunnerCallback) (TimeStamp aDeadline, void* aData);
+
+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();
+  void SetTimerInternal(uint32_t aDelay);
+
+  nsCOMPtr<nsITimer> mTimer;
+  nsCOMPtr<nsITimer> mScheduleTimer;
+  IdleTaskRunnerCallback mCallback;
+  uint32_t mDelay;
+  TimeStamp mDeadline;
+  TimeDuration mBudget;
+  bool mRepeating;
+  bool mTimerActive;
+  void* mData;
+};
+
+} // end of namespace mozilla.
+
+#endif
--- a/xpcom/threads/moz.build
+++ b/xpcom/threads/moz.build
@@ -38,16 +38,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',
     'RecursiveMutex.h',
     'ReentrantMonitor.h',
     'RWLock.h',
@@ -58,16 +59,20 @@ EXPORTS.mozilla += [
     'SyncRunnable.h',
     'SystemGroup.h',
     'TaskCategory.h',
     'TaskDispatcher.h',
     'TaskQueue.h',
     'ThrottledEventQueue.h',
 ]
 
+SOURCES += [
+    'IdleTaskRunner.cpp',
+]
+
 UNIFIED_SOURCES += [
     'AbstractThread.cpp',
     'BackgroundHangMonitor.cpp',
     'BlockingResourceBase.cpp',
     'HangAnnotations.cpp',
     'HangMonitor.cpp',
     'LazyIdleThread.cpp',
     'MainThreadIdlePeriod.cpp',