Bug 1041632 - Part 7: make MemoryMonitor thread-safe. r=ckitching
authorRichard Newman <rnewman@mozilla.com>
Mon, 21 Jul 2014 10:22:45 -0700
changeset 195370 827990281932854dbb5fdb350a9903a5a64bf7b1
parent 195369 e014881a4d8d32e6c6a45a368519d08401a764c7
child 195371 278e109b79f5f363cd90b4da473ec49f249ffb51
push id46575
push userkwierso@gmail.com
push dateTue, 22 Jul 2014 00:35:21 +0000
treeherdermozilla-inbound@fee5c4bdd713 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersckitching
bugs1041632
milestone33.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 1041632 - Part 7: make MemoryMonitor thread-safe. r=ckitching
mobile/android/base/MemoryMonitor.java
--- a/mobile/android/base/MemoryMonitor.java
+++ b/mobile/android/base/MemoryMonitor.java
@@ -35,32 +35,32 @@ import android.util.Log;
   * be thread-safe. In terms of lock ordering, code holding the PressureDecrementer lock
   * is allowed to pick up the MemoryMonitor lock, but not vice-versa.
   */
 class MemoryMonitor extends BroadcastReceiver {
     private static final String LOGTAG = "GeckoMemoryMonitor";
     private static final String ACTION_MEMORY_DUMP = "org.mozilla.gecko.MEMORY_DUMP";
     private static final String ACTION_FORCE_PRESSURE = "org.mozilla.gecko.FORCE_MEMORY_PRESSURE";
 
-    // Memory pressue levels, keep in sync with those in AndroidJavaWrappers.h
+    // Memory pressure levels. Keep these in sync with those in AndroidJavaWrappers.h
     private static final int MEMORY_PRESSURE_NONE = 0;
     private static final int MEMORY_PRESSURE_CLEANUP = 1;
     private static final int MEMORY_PRESSURE_LOW = 2;
     private static final int MEMORY_PRESSURE_MEDIUM = 3;
     private static final int MEMORY_PRESSURE_HIGH = 4;
 
     private static MemoryMonitor sInstance = new MemoryMonitor();
 
     static MemoryMonitor getInstance() {
         return sInstance;
     }
 
     private final PressureDecrementer mPressureDecrementer;
-    private int mMemoryPressure;
-    private boolean mStoragePressure;
+    private int mMemoryPressure;                  // Synchronized access only.
+    private volatile boolean mStoragePressure;    // Accessed via UI thread intent, background runnables.
     private boolean mInited;
 
     private MemoryMonitor() {
         mPressureDecrementer = new PressureDecrementer();
         mMemoryPressure = MEMORY_PRESSURE_NONE;
         mStoragePressure = false;
     }
 
@@ -161,16 +161,23 @@ class MemoryMonitor extends BroadcastRec
                 GeckoAppShell.dispatchMemoryPressure();
             }
 
             Favicons.clearMemCache();
         }
         return true;
     }
 
+    /**
+     * Thread-safe due to mStoragePressure's volatility.
+     */
+    boolean isUnderStoragePressure() {
+        return mStoragePressure;
+    }
+
     private boolean decreaseMemoryPressure() {
         int newLevel;
         synchronized (this) {
             if (mMemoryPressure <= 0) {
                 return false;
             }
 
             newLevel = --mMemoryPressure;
@@ -202,32 +209,32 @@ class MemoryMonitor extends BroadcastRec
                 return;
             }
 
             // need to keep decrementing
             ThreadUtils.getBackgroundHandler().postDelayed(this, DECREMENT_DELAY);
         }
     }
 
-    class StorageReducer implements Runnable {
+    private static class StorageReducer implements Runnable {
         private final Context mContext;
         public StorageReducer(final Context context) {
             this.mContext = context;
         }
 
         @Override
         public void run() {
             // this might get run right on startup, if so wait 10 seconds and try again
             if (!GeckoThread.checkLaunchState(GeckoThread.LaunchState.GeckoRunning)) {
                 ThreadUtils.getBackgroundHandler().postDelayed(this, 10000);
                 return;
             }
 
-            if (!mStoragePressure) {
-                // pressure is off, so we can abort
+            if (!MemoryMonitor.getInstance().isUnderStoragePressure()) {
+                // Pressure is off, so we can abort.
                 return;
             }
 
             BrowserDB.expireHistory(mContext.getContentResolver(),
                                     BrowserContract.ExpirePriority.AGGRESSIVE);
             BrowserDB.removeThumbnails(mContext.getContentResolver());
             // TODO: drop or shrink disk caches
         }