Bug 1213273 - Use a chromium Task instead of an nsITimer for the timeout in TaskThrottler. r=mstange
authorBotond Ballo <botond@mozilla.com>
Fri, 16 Oct 2015 19:00:15 -0400
changeset 303666 3711cda860a1f195cb71213bfa75cd02d84aaebd
parent 303665 7a5670ba45aeeacd3601801c1740ba3bf9115cd0
child 303667 01a5ca4ef014d37dfaec8a8f1ed2d3631fda4ffa
push id1001
push userraliiev@mozilla.com
push dateMon, 18 Jan 2016 19:06:03 +0000
treeherdermozilla-release@8b89261f3ac4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmstange
bugs1213273
milestone44.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 1213273 - Use a chromium Task instead of an nsITimer for the timeout in TaskThrottler. r=mstange
gfx/layers/apz/src/TaskThrottler.cpp
gfx/layers/apz/src/TaskThrottler.h
--- a/gfx/layers/apz/src/TaskThrottler.cpp
+++ b/gfx/layers/apz/src/TaskThrottler.cpp
@@ -1,44 +1,39 @@
 /* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8; -*- */
 /* vim: set sw=2 sts=2 ts=8 et 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 "TaskThrottler.h"
 
-#include "mozilla/layers/APZThreadUtils.h"  // for NewTimerCallback
-#include "nsComponentManagerUtils.h"        // for do_CreateInstance
-#include "nsITimer.h"
+#include "base/message_loop.h"
 
 #define TASK_LOG(...)
 // #define TASK_LOG(...) printf_stderr("TASK: " __VA_ARGS__)
 
 namespace mozilla {
 namespace layers {
 
 TaskThrottler::TaskThrottler(const TimeStamp& aTimeStamp, const TimeDuration& aMaxWait)
   : mMonitor("TaskThrottler")
   , mOutstanding(false)
   , mQueuedTask(nullptr)
   , mStartTime(aTimeStamp)
   , mMaxWait(aMaxWait)
   , mMean(1)
-  , mTimer(do_CreateInstance(NS_TIMER_CONTRACTID))
+  , mTimeoutTask(nullptr)
 {
-  // The TaskThrottler must be created on the main thread (or some nsITimer-
-  // compatible thread) for the nsITimer to work properly. In particular,
-  // creating it on the Compositor thread doesn't work.
-  MOZ_ASSERT(NS_IsMainThread());
 }
 
 TaskThrottler::~TaskThrottler()
 {
-  mTimer->Cancel();
+  // The timeout task holds a strong reference to the TaskThrottler, so if the
+  // TaskThrottler is being destroyed, there's no need to cancel the task.
 }
 
 void
 TaskThrottler::PostTask(const tracked_objects::Location& aLocation,
                         UniquePtr<CancelableTask> aTask, const TimeStamp& aTimeStamp)
 {
   MonitorAutoLock lock(mMonitor);
 
@@ -48,52 +43,56 @@ TaskThrottler::PostTask(const tracked_ob
   if (mOutstanding) {
     CancelPendingTask(lock);
     if (TimeSinceLastRequest(aTimeStamp, lock) < mMaxWait) {
       mQueuedTask = Move(aTask);
       TASK_LOG("%p queued task %p\n", this, mQueuedTask.get());
       // Make sure the queued task is sent after mMaxWait time elapses,
       // even if we don't get a TaskComplete() until then.
       TimeDuration timeout = mMaxWait - TimeSinceLastRequest(aTimeStamp, lock);
-      TimeStamp timeoutTime = mStartTime + mMaxWait;
-      RefPtr<TaskThrottler> refPtrThis = this;
-      mTimer->InitWithCallback(NewTimerCallback(
-          [refPtrThis, timeoutTime]()
-          {
-            MonitorAutoLock lock(refPtrThis->mMonitor);
-            if (refPtrThis->mQueuedTask) {
-              refPtrThis->RunQueuedTask(timeoutTime, lock);
-            }
-          }),
-          timeout.ToMilliseconds(), nsITimer::TYPE_ONE_SHOT);
+      mTimeoutTask = NewRunnableMethod(this, &TaskThrottler::OnTimeout);
+      MessageLoop::current()->PostDelayedTask(FROM_HERE, mTimeoutTask,
+          timeout.ToMilliseconds());
       return;
     }
     // we've been waiting for more than the max-wait limit, so just fall through
     // and send the new task already.
   }
 
   mStartTime = aTimeStamp;
   aTask->Run();
   mOutstanding = true;
 }
 
 void
+TaskThrottler::OnTimeout()
+{
+  MonitorAutoLock lock(mMonitor);
+  if (mQueuedTask) {
+    RunQueuedTask(TimeStamp::Now(), lock);
+  }
+  // The message loop will delete the posted timeout task. Make sure we don't
+  // keep a dangling pointer to it.
+  mTimeoutTask = nullptr;
+}
+
+void
 TaskThrottler::TaskComplete(const TimeStamp& aTimeStamp)
 {
   MonitorAutoLock lock(mMonitor);
 
   if (!mOutstanding) {
     return;
   }
 
   mMean.insert(aTimeStamp - mStartTime);
 
   if (mQueuedTask) {
     RunQueuedTask(aTimeStamp, lock);
-    mTimer->Cancel();
+    CancelTimeoutTask(lock);
   } else {
     mOutstanding = false;
   }
 }
 
 TimeDuration
 TaskThrottler::AverageDuration()
 {
@@ -121,17 +120,26 @@ TaskThrottler::CancelPendingTask()
 
 void
 TaskThrottler::CancelPendingTask(const MonitorAutoLock& aProofOfLock)
 {
   if (mQueuedTask) {
     TASK_LOG("%p cancelling task %p\n", this, mQueuedTask.get());
     mQueuedTask->Cancel();
     mQueuedTask = nullptr;
-    mTimer->Cancel();
+    CancelTimeoutTask(aProofOfLock);
+  }
+}
+
+void
+TaskThrottler::CancelTimeoutTask(const MonitorAutoLock& aProofOfLock)
+{
+  if (mTimeoutTask) {
+    mTimeoutTask->Cancel();
+    mTimeoutTask = nullptr;  // the MessageLoop will destroy it
   }
 }
 
 TimeDuration
 TaskThrottler::TimeSinceLastRequest(const TimeStamp& aTimeStamp)
 {
   MonitorAutoLock lock(mMonitor);
   return TimeSinceLastRequest(aTimeStamp, lock);
--- a/gfx/layers/apz/src/TaskThrottler.h
+++ b/gfx/layers/apz/src/TaskThrottler.h
@@ -13,18 +13,16 @@
 #include "mozilla/mozalloc.h"           // for operator delete
 #include "mozilla/RollingMean.h"        // for RollingMean
 #include "mozilla/TimeStamp.h"          // for TimeDuration, TimeStamp
 #include "mozilla/UniquePtr.h"          // for UniquePtr
 #include "nsCOMPtr.h"                   // for nsCOMPtr
 #include "nsISupportsImpl.h"            // for NS_INLINE_DECL_THREADSAFE_REFCOUNTING
 #include "nsTArray.h"                   // for nsTArray
 
-class nsITimer;
-
 namespace tracked_objects {
 class Location;
 } // namespace tracked_objects
 
 namespace mozilla {
 namespace layers {
 
 /** The TaskThrottler prevents update event overruns. It is used in cases where
@@ -97,22 +95,25 @@ public:
 
 private:
   mutable Monitor mMonitor;
   bool mOutstanding;
   UniquePtr<CancelableTask> mQueuedTask;
   TimeStamp mStartTime;
   TimeDuration mMaxWait;
   RollingMean<TimeDuration, TimeDuration> mMean;
-  nsCOMPtr<nsITimer> mTimer;
+  CancelableTask* mTimeoutTask;  // not owned because it's posted to a MessageLoop
+                                 // which deletes it
 
   ~TaskThrottler();
   void RunQueuedTask(const TimeStamp& aTimeStamp,
                      const MonitorAutoLock& aProofOfLock);
   void CancelPendingTask(const MonitorAutoLock& aProofOfLock);
   TimeDuration TimeSinceLastRequest(const TimeStamp& aTimeStamp,
                                     const MonitorAutoLock& aProofOfLock);
+  void OnTimeout();
+  void CancelTimeoutTask(const MonitorAutoLock& aProofOfLock);
 };
 
 } // namespace layers
 } // namespace mozilla
 
 #endif // mozilla_dom_TaskThrottler_h