Bug 1389479 - Part 1. Add nsExpirationTracker::NotifyEndTransaction(Locked) callbacks for subclasses to know when an aging iteration is complete. r=froydnj
authorAndrew Osmond <aosmond@mozilla.com>
Tue, 15 Aug 2017 15:02:14 -0400
changeset 374825 635b60924015ec2379e3e4f092f2cd54b587fd17
parent 374824 7dcd9537f6fa8fef8830739beabb93132b6603fe
child 374826 3f2e443dd48ce187ba6098e2a72fd5804f94c6f3
push id93778
push useraosmond@gmail.com
push dateTue, 15 Aug 2017 19:02:24 +0000
treeherdermozilla-inbound@9ddc28603bea [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj
bugs1389479
milestone57.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 1389479 - Part 1. Add nsExpirationTracker::NotifyEndTransaction(Locked) callbacks for subclasses to know when an aging iteration is complete. r=froydnj
xpcom/ds/nsExpirationTracker.h
--- a/xpcom/ds/nsExpirationTracker.h
+++ b/xpcom/ds/nsExpirationTracker.h
@@ -350,16 +350,30 @@ protected:
    * and should be avoided (we'll issue a warning). (This recycling counts
    * as "a use" for the purposes of the expiry guarantee above...)
    *
    * For robustness and simplicity, we allow objects to be notified more than
    * once here in the same timer tick.
    */
   virtual void NotifyExpiredLocked(T*, const AutoLock&) = 0;
 
+  /**
+   * This may be overridden to perform any post-aging work that needs to be
+   * done while still holding the lock. It will be called once after each timer
+   * event, and each low memory event has been handled.
+   */
+  virtual void NotifyHandlerEndLocked(const AutoLock&) { };
+
+  /**
+   * This may be overridden to perform any post-aging work that needs to be
+   * done outside the lock. It will be called once after each
+   * NotifyEndTransactionLocked call.
+   */
+  virtual void NotifyHandlerEnd() { };
+
   virtual Mutex& GetMutex() = 0;
 
 private:
   class ExpirationTrackerObserver;
   RefPtr<ExpirationTrackerObserver> mObserver;
   nsTArray<T*>       mGenerations[K];
   nsCOMPtr<nsITimer> mTimer;
   uint32_t           mTimerPeriod;
@@ -393,28 +407,36 @@ private:
     }
     NS_DECL_ISUPPORTS
     NS_DECL_NSIOBSERVER
   private:
     ExpirationTrackerImpl<T, K, Mutex, AutoLock>* mOwner;
   };
 
   void HandleLowMemory() {
-    AutoLock lock(GetMutex());
-    AgeAllGenerationsLocked(lock);
+    {
+      AutoLock lock(GetMutex());
+      AgeAllGenerationsLocked(lock);
+      NotifyHandlerEndLocked(lock);
+    }
+    NotifyHandlerEnd();
   }
 
   void HandleTimeout() {
-    AutoLock lock(GetMutex());
-    AgeOneGenerationLocked(lock);
-    // Cancel the timer if we have no objects to track
-    if (IsEmptyLocked(lock)) {
-      mTimer->Cancel();
-      mTimer = nullptr;
+    {
+      AutoLock lock(GetMutex());
+      AgeOneGenerationLocked(lock);
+      // Cancel the timer if we have no objects to track
+      if (IsEmptyLocked(lock)) {
+        mTimer->Cancel();
+        mTimer = nullptr;
+      }
+      NotifyHandlerEndLocked(lock);
     }
+    NotifyHandlerEnd();
   }
 
   static void TimerCallback(nsITimer* aTimer, void* aThis)
   {
     ExpirationTrackerImpl* tracker = static_cast<ExpirationTrackerImpl*>(aThis);
     tracker->HandleTimeout();
   }
 
@@ -486,16 +508,24 @@ class nsExpirationTracker : protected ::
     return mLock;
   }
 
   void NotifyExpiredLocked(T* aObject, const AutoLock&) override
   {
     NotifyExpired(aObject);
   }
 
+  /**
+   * Since there are no users of these callbacks in the single threaded case,
+   * we mark them as final with the hope that the compiler can optimize the
+   * method calls out entirely.
+   */
+  void NotifyHandlerEndLocked(const AutoLock&) final override { }
+  void NotifyHandlerEnd() final override { }
+
 protected:
   virtual void NotifyExpired(T* aObj) = 0;
 
 public:
   nsExpirationTracker(uint32_t aTimerPeriod,
                       const char* aName,
                       nsIEventTarget* aEventTarget = nullptr)
     : ::detail::SingleThreadedExpirationTracker<T, K>(aTimerPeriod,