OSDN Git Service

ART: Make test 030 slightly more robust
authorAndreas Gampe <agampe@google.com>
Thu, 10 Nov 2016 22:09:05 +0000 (14:09 -0800)
committerAndreas Gampe <agampe@google.com>
Thu, 10 Nov 2016 22:18:17 +0000 (14:18 -0800)
Run a serious of immediate GCs, synchronizer with the finalizer
starintg  and then let the main thread sleep for a minute, in an
effort to make the test deterministic and get the finalizer
daemon scheduled.

Test: m test-art-host-run-test-030-bad-finalizer
Change-Id: Id379d8147ecc8f6aa0a7d8d5058030a4c2d4de46

test/030-bad-finalizer/expected.txt
test/030-bad-finalizer/src/Main.java

index ee9cfff..74e208c 100644 (file)
@@ -1,4 +1,4 @@
-About to null reference and request GC.
+About to null reference.
 Finalizer started and spinning...
 Finalizer done spinning.
 Finalizer sleeping forever now.
index 942ee25..0e69a96 100644 (file)
  * limitations under the License.
  */
 
+import java.util.concurrent.CountDownLatch;
+import static java.util.concurrent.TimeUnit.MINUTES;
+
 /**
  * Test a class with a bad finalizer.
+ *
+ * This test is inherently flaky. It assumes that the system will schedule the finalizer daemon
+ * and finalizer watchdog daemon enough to reach the timeout and throwing the fatal exception.
  */
 public class Main {
-    public static void main(String[] args) {
-        BadFinalizer bf = new BadFinalizer();
+    public static void main(String[] args) throws Exception {
+        CountDownLatch finalizerWait = new CountDownLatch(1);
 
-        System.out.println("About to null reference and request GC.");
-        bf = null;
-        Runtime.getRuntime().gc();
+        // A separate method to ensure no dex register keeps the object alive.
+        createBadFinalizer(finalizerWait);
 
-        for (int i = 0; i < 8; i++) {
-            snooze(4000);
+        // Should have at least two iterations to trigger finalization, but just to make sure run
+        // some more.
+        for (int i = 0; i < 5; i++) {
             Runtime.getRuntime().gc();
         }
 
+        // Now wait for the finalizer to start running. Give it a minute.
+        finalizerWait.await(1, MINUTES);
+
+        // Now fall asleep with a timeout. The timeout is large enough that we expect the
+        // finalizer daemon to have killed the process before the deadline elapses.
+        // Note: the timeout is here (instead of an infinite sleep) to protect the test
+        //       environment (e.g., in case this is run without a timeout wrapper).
+        final long timeout = 60 * 1000;  // 1 minute.
+        long remainingWait = timeout;
+        final long waitStart = System.currentTimeMillis();
+        while (remainingWait > 0) {
+            synchronized (args) {  // Just use an already existing object for simplicity...
+                try {
+                    args.wait(remainingWait);
+                } catch (Exception e) {
+                }
+            }
+            remainingWait = timeout - (System.currentTimeMillis() - waitStart);
+        }
+
+        // We should not get here.
         System.out.println("UNREACHABLE");
         System.exit(0);
     }
 
+    private static void createBadFinalizer(CountDownLatch finalizerWait) {
+        BadFinalizer bf = new BadFinalizer(finalizerWait);
+
+        System.out.println("About to null reference.");
+        bf = null;  // Not that this would make a difference, could be eliminated earlier.
+    }
+
     public static void snooze(int ms) {
         try {
             Thread.sleep(ms);
@@ -45,9 +79,17 @@ public class Main {
      * Class with a bad finalizer.
      */
     public static class BadFinalizer {
+        private CountDownLatch finalizerWait;
+        private volatile int j = 0;  // Volatile in an effort to curb loop optimization.
+
+        public BadFinalizer(CountDownLatch finalizerWait) {
+            this.finalizerWait = finalizerWait;
+        }
+
         protected void finalize() {
+            finalizerWait.countDown();
+
             System.out.println("Finalizer started and spinning...");
-            int j = 0;
 
             /* spin for a bit */
             long start, end;