fixup! Bug 1313864 - Make IdleRequest dispatch itself. r?bkelly draft
authorAndreas Farre <farre@mozilla.com>
Wed, 16 Nov 2016 18:13:01 +0100
changeset 439804 7d7530e4d7ed8c03753932fc5235d41bce5a1d68
parent 439803 339c3880fbacc7de0c927c1d1d04e43289f9e16d
child 537260 d2c024d6efffb0d420734a9206b38bb481cad641
push id36100
push userbmo:afarre@mozilla.com
push dateWed, 16 Nov 2016 17:13:28 +0000
reviewersbkelly
bugs1313864
milestone52.0a1
fixup! Bug 1313864 - Make IdleRequest dispatch itself. r?bkelly
dom/base/IdleRequest.cpp
dom/base/RunnableTimeoutHandler.cpp
dom/base/RunnableTimeoutHandler.h
dom/base/nsGlobalWindow.cpp
--- a/dom/base/IdleRequest.cpp
+++ b/dom/base/IdleRequest.cpp
@@ -73,16 +73,17 @@ IdleRequest::SetTimeout(uint32_t aTimeou
 
   return rv;
 }
 
 void
 IdleRequest::Dispatch()
 {
   MOZ_ASSERT(NS_IsMainThread());
+  MOZ_DIAGNOSTIC_ASSERT(!mRunning);
 
   RefPtr<IdleRequest> kungFuDeathGrip(this);
   NS_IdleDispatchToCurrentThread(kungFuDeathGrip.forget());
   mRunning = true;
 }
 
 nsresult
 IdleRequest::Run()
@@ -124,22 +125,23 @@ nsresult
 IdleRequest::RunIdleRequestCallback(bool aDidTimeout)
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   if (!aDidTimeout) {
     CancelTimeout();
   }
 
-  remove();
   ErrorResult error;
   RefPtr<IdleDeadline> deadline =
     new IdleDeadline(mWindow, aDidTimeout, mDeadline);
   mCallback->Call(*deadline, error, "requestIdleCallback handler");
   mCallback = nullptr;
+
+  remove();
   Release();
 
   nsGlobalWindow::Cast(mWindow)->DispatchNextIdleRequest();
 
   return error.StealNSResult();
 }
 
 void
--- a/dom/base/RunnableTimeoutHandler.cpp
+++ b/dom/base/RunnableTimeoutHandler.cpp
@@ -10,16 +10,17 @@
 
 namespace mozilla {
 namespace dom {
 
 RunnableTimeoutHandler::RunnableTimeoutHandler(
   already_AddRefed<nsIRunnable> aRunnable)
   : mRunnable(Move(aRunnable))
 {
+  MOZ_ASSERT(mRunnable);
 }
 
 nsresult
 RunnableTimeoutHandler::Call()
 {
   return mRunnable->Run();
 }
 
--- a/dom/base/RunnableTimeoutHandler.h
+++ b/dom/base/RunnableTimeoutHandler.h
@@ -15,17 +15,17 @@
 class nsIRunnable;
 
 namespace mozilla {
 namespace dom {
 
 class RunnableTimeoutHandler final : public nsITimeoutHandler
 {
 public:
-  RunnableTimeoutHandler(already_AddRefed<nsIRunnable> aRunnable);
+  explicit RunnableTimeoutHandler(already_AddRefed<nsIRunnable> aRunnable);
   virtual nsresult Call() override;
   virtual void GetLocation(const char** aFileName, uint32_t* aLineNo,
                            uint32_t* aColumn) override;
   virtual void MarkForCC() override {}
 
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_CYCLE_COLLECTION_CLASS(RunnableTimeoutHandler)
 
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -575,22 +575,28 @@ nsGlobalWindow::DispatchNextIdleRequest(
     return;
   }
 
   nsGlobalWindow* outer = GetOuterWindowInternal();
   if (outer && outer->AsOuter()->IsBackground()) {
     int32_t dummy;
     RefPtr<RunnableTimeoutHandler> timeout(new RunnableTimeoutHandler(
       NewRunnableMethod(this, &nsGlobalWindow::DispatchIdleRequest)));
-    SetTimeoutOrInterval(timeout, 0, false, Timeout::Reason::eInternalTimeout,
-                         &dummy);
-  } else {
-    RefPtr<IdleRequest> request(mIdleRequestCallbacks.getFirst());
-    request->Dispatch();
-  }
+    // We really want to re-use the mechanisms in SetTimeoutOrInterval
+    // to handle throttling, but due to Bug 1316871 we can't do that
+    // yet. When that is fixed we can instead of passing
+    // gMinBackgroundTimeoutValue just pass 0.
+    SetTimeoutOrInterval(timeout, gMinBackgroundTimeoutValue, false,
+                         Timeout::Reason::eInternalTimeout, &dummy);
+
+    return;
+  }
+
+  RefPtr<IdleRequest> request(mIdleRequestCallbacks.getFirst());
+  request->Dispatch();
 }
 
 /* static */ void
 nsGlobalWindow::InsertIdleCallbackIntoList(IdleRequest* aRequest,
                                            IdleRequests& aList)
 {
   aList.insertBack(aRequest);
   aRequest->AddRef();
@@ -612,16 +618,19 @@ nsGlobalWindow::RequestIdleCallback(JSCo
 
   if (aOptions.mTimeout.WasPassed()) {
     aError = request->SetTimeout(aOptions.mTimeout.Value());
     if (NS_WARN_IF(aError.Failed())) {
       return 0;
     }
   }
 
+  // If the list of idle callback requests is not empty it means that
+  // we've already dispatched the first idle request. It is the
+  // responsibility of that to dispatch the next.
   bool needsScheduling = mIdleRequestCallbacks.isEmpty();
   // mIdleRequestCallbacks now owns request
   InsertIdleCallbackIntoList(request, mIdleRequestCallbacks);
 
   if (needsScheduling) {
     DispatchNextIdleRequest();
   }
 
@@ -12481,18 +12490,19 @@ uint32_t sNestingLevel;
 uint32_t
 nsGlobalWindow::GetTimeoutId(Timeout::Reason aReason)
 {
   switch (aReason) {
     case Timeout::Reason::eIdleCallbackTimeout:
       return ++mIdleCallbackTimeoutCounter;
     case Timeout::Reason::eTimeoutOrInterval:
       return ++mTimeoutIdCounter;
+    default:
+      MOZ_ASSERT_UNREACHABLE("Unhandled timeout reason");
     case Timeout::Reason::eInternalTimeout:
-    default:
       return 0;
   }
 }
 
 nsGlobalWindow*
 nsGlobalWindow::InnerForSetTimeoutOrInterval(ErrorResult& aError)
 {
   nsGlobalWindow* currentInner;