Only allow one requestGC at a time

Fixes possible deadlock caused by Thread.getAllStackTraces

Thread.getAllStackTraces suspends all of the threads. If one of
the threads is a thread which holds the GC daemon lock then we
may deadlock when we allocate the stack trace. This happens if we
get a concurrent GC request when we are allocating the stack trace
elements. To fix the deadlock we now only allow a single thread to
requestGC at the same time.

Credits: yamauchi, hboehm

Bug: 18661622

(cherry picked from commit c0b55b80df57b9f8c659a5af4525ceba271622b6)

Change-Id: Iba46cb9c6cd2503d7af3348b4478c8c53973b9ee
diff --git a/libart/src/main/java/java/lang/Daemons.java b/libart/src/main/java/java/lang/Daemons.java
index 6b3344c..485f2c9 100644
--- a/libart/src/main/java/java/lang/Daemons.java
+++ b/libart/src/main/java/java/lang/Daemons.java
@@ -20,6 +20,7 @@
 import java.lang.ref.FinalizerReference;
 import java.lang.ref.Reference;
 import java.lang.ref.ReferenceQueue;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.TimeoutException;
 import libcore.util.EmptyArray;
 
@@ -323,11 +324,16 @@
 
     private static class GCDaemon extends Daemon {
         private static final GCDaemon INSTANCE = new GCDaemon();
+        private static final AtomicBoolean atomicBoolean = new AtomicBoolean();
 
         public void requestGC() {
+            if (atomicBoolean.getAndSet(true)) {
+              return;
+            }
             synchronized (this) {
                 notify();
             }
+            atomicBoolean.set(false);
         }
 
         @Override public void run() {