Bug 987415 - Part 1: GeckoAppShell thread-safety. r=bnicholson
authorRichard Newman <rnewman@mozilla.com>
Mon, 24 Mar 2014 17:44:02 -0700
changeset 175139 b4fce211dbdea20d897b78c5cf5df080b83226ee
parent 175138 54e12e5102643b63f3c410667eaacebeb043894e
child 175140 f353b6a98a3d49ab41a7bd9ce13c07101b623b93
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersbnicholson
bugs987415
milestone31.0a1
Bug 987415 - Part 1: GeckoAppShell thread-safety. r=bnicholson
mobile/android/base/GeckoAppShell.java
--- a/mobile/android/base/GeckoAppShell.java
+++ b/mobile/android/base/GeckoAppShell.java
@@ -15,25 +15,26 @@ import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.OutputStream;
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.net.Proxy;
 import java.net.URL;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.Iterator;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.NoSuchElementException;
+import java.util.Queue;
 import java.util.StringTokenizer;
 import java.util.TreeMap;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentLinkedQueue;
 
 import org.mozilla.gecko.favicons.OnFaviconLoadedListener;
 import org.mozilla.gecko.favicons.decoders.FaviconDecoder;
 import org.mozilla.gecko.gfx.BitmapUtils;
 import org.mozilla.gecko.gfx.GeckoLayerClient;
 import org.mozilla.gecko.gfx.LayerView;
 import org.mozilla.gecko.gfx.PanZoomController;
 import org.mozilla.gecko.mozglue.GeckoLoader;
@@ -117,18 +118,18 @@ public class GeckoAppShell
     private static final boolean LOGGING = false;
 
     // We have static members only.
     private GeckoAppShell() { }
 
     private static boolean restartScheduled = false;
     private static GeckoEditableListener editableListener = null;
 
-    private static final LinkedList<GeckoEvent> PENDING_EVENTS = new LinkedList<GeckoEvent>();
-    private static final HashMap<String, String> ALERT_COOKIES = new HashMap<String, String>();
+    private static final Queue<GeckoEvent> PENDING_EVENTS = new ConcurrentLinkedQueue<GeckoEvent>();
+    private static final Map<String, String> ALERT_COOKIES = new ConcurrentHashMap<String, String>();
 
     private static volatile boolean locationHighAccuracyEnabled;
 
     // Accessed by NotificationHelper. This should be encapsulated.
     /* package */ static NotificationClient notificationClient;
 
     // See also HardwareUtils.LOW_MEMORY_THRESHOLD_MB.
     private static final int HIGH_MEMORY_DEVICE_THRESHOLD_MB = 768;
@@ -352,31 +353,52 @@ public class GeckoAppShell
         GeckoEditable editable = new GeckoEditable();
         // install the gecko => editable listener
         editableListener = editable;
     }
 
     static void sendPendingEventsToGecko() {
         try {
             while (!PENDING_EVENTS.isEmpty()) {
-                GeckoEvent e = PENDING_EVENTS.removeFirst();
+                final GeckoEvent e = PENDING_EVENTS.poll();
                 notifyGeckoOfEvent(e);
             }
         } catch (NoSuchElementException e) {}
     }
 
+    /**
+     * If the Gecko thread is running, immediately dispatches the event to
+     * Gecko.
+     *
+     * If the Gecko thread is not running, queues the event. If the queue is
+     * full, throws {@link IllegalStateException}.
+     *
+     * Queued events will be dispatched in order of arrival when the Gecko
+     * thread becomes live.
+     *
+     * This method can be called from any thread.
+     *
+     * @param e
+     *            the event to dispatch. Cannot be null.
+     */
     @RobocopTarget
     public static void sendEventToGecko(GeckoEvent e) {
+        if (e == null) {
+            throw new IllegalArgumentException("e cannot be null.");
+        }
+
         if (GeckoThread.checkLaunchState(GeckoThread.LaunchState.GeckoRunning)) {
             notifyGeckoOfEvent(e);
-            // Gecko will copy the event data into a normal C++ object. We can recycle the evet now.
+            // Gecko will copy the event data into a normal C++ object. We can recycle the event now.
             e.recycle();
-        } else {
-            PENDING_EVENTS.addLast(e);
+            return;
         }
+
+        // Throws if unable to add the event due to capacity restrictions.
+        PENDING_EVENTS.add(e);
     }
 
     // Tell the Gecko event loop that an event is available.
     public static native void notifyGeckoOfEvent(GeckoEvent event);
 
     /*
      *  The Gecko-side API: API methods that Gecko calls
      */