Bug 1335148 - Part 2: Introduce notification for end of memory pressure. r?gsvelto draft
authorJan Henning <jh+bugzilla@buttercookie.de>
Fri, 30 Mar 2018 13:26:24 +0200
changeset 793278 2147d58661f98c49b905d032975c0422ed8cffc1
parent 793277 21e61d8cef8108bdf41dff3cd3586255d6545e06
child 793279 224fae405615cb81e4cb2f5176960538c2dbba8d
push id109332
push usermozilla@buttercookie.de
push dateWed, 09 May 2018 19:48:41 +0000
reviewersgsvelto
bugs1335148
milestone62.0a1
Bug 1335148 - Part 2: Introduce notification for end of memory pressure. r?gsvelto For Fennec on Android, if we haven't received memory pressure notifications from the OS for a certain amount of time (in the order of ~15 mins), we assume that we're no longer under memory pressure. In order to turn the bfcache back on when that happens, we now want to be able to forward this fact to Gecko as well. Unfortunately, the way memory pressure is tracked using an atomic variable doesn't easily allow to fully extend the existing priority rules between "new" and "ongoing" to include a new "stopping of memory pressure" event. Since we're not using Dispatch*Eventual*MemoryPressure on Android and therefore the queuing priority behaviour isn't actually relevant for us, we just ignore that and only enforce that a pending "new" memory pressure event takes priority over a "stop" event. MozReview-Commit-ID: 90C9KogUyvf
xpcom/threads/nsMemoryPressure.cpp
xpcom/threads/nsMemoryPressure.h
xpcom/threads/nsThread.cpp
--- a/xpcom/threads/nsMemoryPressure.cpp
+++ b/xpcom/threads/nsMemoryPressure.cpp
@@ -22,30 +22,31 @@ NS_GetPendingMemoryPressure()
   int32_t value = sMemoryPressurePending.exchange(MemPressure_None);
   return MemoryPressureState(value);
 }
 
 void
 NS_DispatchEventualMemoryPressure(MemoryPressureState aState)
 {
   /*
-   * A new memory pressure event erases an ongoing memory pressure, but an
-   * existing "new" memory pressure event takes precedence over a new "ongoing"
-   * memory pressure event.
+   * A new memory pressure event erases an ongoing (or stop of) memory pressure,
+   * but an existing "new" memory pressure event takes precedence over a new
+   * "ongoing" or "stop" memory pressure event.
    */
   switch (aState) {
     case MemPressure_None:
       sMemoryPressurePending = MemPressure_None;
       break;
     case MemPressure_New:
       sMemoryPressurePending = MemPressure_New;
       break;
     case MemPressure_Ongoing:
+    case MemPressure_Stopping:
       sMemoryPressurePending.compareExchange(MemPressure_None,
-                                             MemPressure_Ongoing);
+                                             aState);
       break;
   }
 }
 
 nsresult
 NS_DispatchMemoryPressure(MemoryPressureState aState)
 {
   NS_DispatchEventualMemoryPressure(aState);
--- a/xpcom/threads/nsMemoryPressure.h
+++ b/xpcom/threads/nsMemoryPressure.h
@@ -35,17 +35,28 @@ enum MemoryPressureState
    *
    * In case of conflict with an new memory pressue, the new memory pressure
    * takes precedence over an ongoing memory pressure.  The reason being
    * that if no events are processed between 2 notifications (new followed
    * by ongoing, or ongoing followed by a new) we want to be as aggresive as
    * possible on the clean-up of the memory.  After all, we are trying to
    * keep Gecko alive as long as possible.
    */
-  MemPressure_Ongoing
+  MemPressure_Ongoing,
+
+  /*
+   * Memory pressure stopped.
+   *
+   * We're no longer under acute memory pressure, so we might want to have a
+   * chance of (cautiously) re-enabling some things we previously turned off.
+   * As above, an already enqueued new memory pressure event takes precedence.
+   * The priority ordering between concurrent attempts to queue both stopped
+   * and ongoing memory pressure is currently not defined.
+   */
+  MemPressure_Stopping
 };
 
 /**
  * Return and erase the latest state of the memory pressure event set by any of
  * the corresponding dispatch function.
  */
 MemoryPressureState
 NS_GetPendingMemoryPressure();
--- a/xpcom/threads/nsThread.cpp
+++ b/xpcom/threads/nsThread.cpp
@@ -1263,21 +1263,25 @@ nsThread::DoMainThreadSpecificProcessing
 
   // Fire a memory pressure notification, if one is pending.
   if (!ShuttingDown()) {
     MemoryPressureState mpPending = NS_GetPendingMemoryPressure();
     if (mpPending != MemPressure_None) {
       nsCOMPtr<nsIObserverService> os = services::GetObserverService();
 
       if (os) {
-        // Use no-forward to prevent the notifications from being transferred to
-        // the children of this process.
-        os->NotifyObservers(nullptr, "memory-pressure",
-                            mpPending == MemPressure_New ? u"low-memory-no-forward" :
-                            u"low-memory-ongoing-no-forward");
+        if (mpPending == MemPressure_Stopping) {
+          os->NotifyObservers(nullptr, "memory-pressure-stop", nullptr);
+        } else {
+          // Use no-forward to prevent the notifications from being transferred to
+          // the children of this process.
+          os->NotifyObservers(nullptr, "memory-pressure",
+                              mpPending == MemPressure_New ? u"low-memory-no-forward" :
+                              u"low-memory-ongoing-no-forward");
+        }
       } else {
         NS_WARNING("Can't get observer service!");
       }
     }
   }
 
   if (!ShuttingDown()) {
     SaveMemoryReportNearOOM(ShouldSaveMemoryReport::kMaybeReport);