Merge "Fix race between finalizeAllEnqueued and GC" into lmp-dev
diff --git a/luni/src/main/java/java/lang/ref/FinalizerReference.java b/luni/src/main/java/java/lang/ref/FinalizerReference.java
index 47dc0b4..5416a80 100644
--- a/luni/src/main/java/java/lang/ref/FinalizerReference.java
+++ b/luni/src/main/java/java/lang/ref/FinalizerReference.java
@@ -83,12 +83,18 @@
      * Waits for all currently-enqueued references to be finalized.
      */
     public static void finalizeAllEnqueued() throws InterruptedException {
-        Sentinel sentinel = new Sentinel();
-        enqueueSentinelReference(sentinel);
+        // Alloate a new sentinel, this creates a FinalizerReference.
+        Sentinel sentinel;
+        // Keep looping until we safely enqueue our sentinel FinalizerReference.
+        // This is done to prevent races where the GC updates the pendingNext
+        // before we get the chance.
+        do {
+            sentinel = new Sentinel();
+        } while (!enqueueSentinelReference(sentinel));
         sentinel.awaitFinalization();
     }
 
-    private static void enqueueSentinelReference(Sentinel sentinel) {
+    private static boolean enqueueSentinelReference(Sentinel sentinel) {
         synchronized (LIST_LOCK) {
             // When a finalizable object is allocated, a FinalizerReference is added to the list.
             // We search the list for that FinalizerReference (it should be at or near the head),
@@ -103,9 +109,15 @@
                     // since there could be recently freed objects in the unqueued list which are not
                     // yet on the finalizer queue. This could cause the sentinel to run before the
                     // objects are finalized. b/17381967
-                    sentinelReference.pendingNext = sentinelReference;
+                    // Make circular list if unenqueued goes through native so that we can prevent
+                    // races where the GC updates the pendingNext before we do. If it is non null, then
+                    // we update the pending next to make a circular list while holding a lock.
+                    // b/17462553
+                    if (!sentinelReference.makeCircularListIfUnenqueued()) {
+                        return false;
+                    }
                     ReferenceQueue.add(sentinelReference);
-                    return;
+                    return true;
                 }
             }
         }
@@ -114,6 +126,8 @@
         throw new AssertionError("newly-created live Sentinel not on list!");
     }
 
+    private native boolean makeCircularListIfUnenqueued();
+
     /**
      * A marker object that we can immediately enqueue. When this object's
      * finalize() method is called, we know all previously-enqueued finalizable