Bug 1062377 - Rewrite GeckoBackgroundThread to not wait for thread start if possible; r=rnewman
authorJim Chen <nchen@mozilla.com>
Tue, 30 Sep 2014 18:19:25 -0400
changeset 208071 c8c23bb480ec0aabdfcadb2f557a3bfcf96b3ec3
parent 208070 b37f591b400e4ce5a1a37bf0d9d18f9c605641d7
child 208072 aa2cf626b77ebb019d56f160efbbfd5aafad0bba
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersrnewman
bugs1062377
milestone35.0a1
Bug 1062377 - Rewrite GeckoBackgroundThread to not wait for thread start if possible; r=rnewman When GeckoBackgroundThread is first used, it starts a new thread and waits for a Handler. This can delay startup. Instead, we can just save the Runnable and run it when the thread is starting.
mobile/android/base/util/GeckoBackgroundThread.java
--- a/mobile/android/base/util/GeckoBackgroundThread.java
+++ b/mobile/android/base/util/GeckoBackgroundThread.java
@@ -7,49 +7,70 @@ package org.mozilla.gecko.util;
 import android.os.Handler;
 import android.os.Looper;
 
 import java.util.concurrent.SynchronousQueue;
 
 final class GeckoBackgroundThread extends Thread {
     private static final String LOOPER_NAME = "GeckoBackgroundThread";
 
-    // Guarded by 'this'.
-    private static Handler sHandler;
-    private SynchronousQueue<Handler> mHandlerQueue = new SynchronousQueue<Handler>();
+    // Guarded by 'GeckoBackgroundThread.class'.
+    private static Handler handler;
+    private static Thread thread;
+
+    // The initial Runnable to run on the new thread. Its purpose
+    // is to avoid us having to wait for the new thread to start.
+    private Runnable initialRunnable;
 
     // Singleton, so private constructor.
-    private GeckoBackgroundThread() {
-        super();
+    private GeckoBackgroundThread(final Runnable initialRunnable) {
+        this.initialRunnable = initialRunnable;
     }
 
     @Override
     public void run() {
         setName(LOOPER_NAME);
         Looper.prepare();
-        try {
-            mHandlerQueue.put(new Handler());
-        } catch (InterruptedException ie) {}
+
+        synchronized (GeckoBackgroundThread.class) {
+            handler = new Handler();
+            GeckoBackgroundThread.class.notify();
+        }
+
+        if (initialRunnable != null) {
+            initialRunnable.run();
+            initialRunnable = null;
+        }
 
         Looper.loop();
     }
 
+    private static void startThread(final Runnable initialRunnable) {
+        thread = new GeckoBackgroundThread(initialRunnable);
+        ThreadUtils.setBackgroundThread(thread);
+
+        thread.setDaemon(true);
+        thread.start();
+    }
+
     // Get a Handler for a looper thread, or create one if it doesn't yet exist.
     /*package*/ static synchronized Handler getHandler() {
-        if (sHandler == null) {
-            GeckoBackgroundThread lt = new GeckoBackgroundThread();
-            ThreadUtils.setBackgroundThread(lt);
-            lt.start();
+        if (thread == null) {
+            startThread(null);
+        }
+
+        while (handler == null) {
             try {
-                sHandler = lt.mHandlerQueue.take();
-            } catch (InterruptedException ie) {}
+                GeckoBackgroundThread.class.wait();
+            } catch (final InterruptedException e) {
+            }
         }
-        return sHandler;
+        return handler;
     }
 
-    /*package*/ static void post(Runnable runnable) {
-        Handler handler = getHandler();
-        if (handler == null) {
-            throw new IllegalStateException("No handler! Must have been interrupted. Not posting.");
+    /*package*/ static synchronized void post(final Runnable runnable) {
+        if (thread == null) {
+            startThread(runnable);
+            return;
         }
-        handler.post(runnable);
+        getHandler().post(runnable);
     }
 }