# HG changeset patch # User jbachorik # Date 1444923342 -7200 # Node ID 08f642d9214f81546c903eff306bc23c50fbeffa # Parent 32b706c7c6a0b8db7600c88562ff86c836cdd6ef 8135188: RunFinalizationTest.java Exception java.lang.Error: Test failure: Object was not finalized Reviewed-by: dcubed, martin diff -r 32b706c7c6a0 -r 08f642d9214f hotspot/test/serviceability/dcmd/gc/FinalizationRunner.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/serviceability/dcmd/gc/FinalizationRunner.java Thu Oct 15 17:35:42 2015 +0200 @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.util.concurrent.CountDownLatch; + +import jdk.test.lib.dcmd.CommandExecutor; +import jdk.test.lib.dcmd.JMXExecutor; + +public class FinalizationRunner { + public static final String FAILED = "Failed"; + public static final String PASSED = "Passed"; + + static volatile boolean wasFinalized = false; + private static final CountDownLatch finRunLatch = new CountDownLatch(1); + private static final CountDownLatch finBlockLatch = new CountDownLatch(1); + + static class MyObject { + @Override + protected void finalize() { + if (Thread.currentThread().getName().equals("Finalizer")) { + try { + System.out.println("inside the regular finalizer thread; blocking"); + // 'regular' finalizer thread is ready to be effectively blocked - + // we can continue with the GC.run_finalization test + finRunLatch.countDown(); + // prevent the 'regular' finalizer from finalizing this instance + // until the GC.run_finalization has had its chance to do so + finBlockLatch.await(); + } catch (InterruptedException e) { + } + } else { + if (Thread.currentThread().getName().equals("Secondary finalizer")) { + System.out.println("finalizing the test instance"); + // finalizing on behalf of GC.run_finalization - + // unblock the 'regular' finalizer and the test main method + wasFinalized = true; + } else { + fail("Unexpected finalizer thread name: " + + Thread.currentThread().getName()); + } + finBlockLatch.countDown(); + } + } + } + + // this instance will be used to provoke the regular finalization + // so the finalizer thread can be blocked for the duration of + // GC.run_finalization test + public static MyObject o1; + + // this instance will be used to perform the GC.run_finalization test + public static MyObject o2; + + private static void run(CommandExecutor executor) { + o2 = new MyObject(); + o2 = null; + System.out.println("running GC.run_finalization"); + System.gc(); + executor.execute("GC.run_finalization"); + + System.out.println("Waiting for finalization"); + + try { + finBlockLatch.await(); + if (wasFinalized) { + System.out.println(PASSED + ": Object was finalized"); + } else { + fail("Object was not finalized"); + } + } catch (InterruptedException e) { + fail("Interrupted while waiting for finalization", e); + } + } + + public static void main(String ... args) { + System.out.println("\n=== FinalizationRunner"); + try { + blockFinalizerThread(); + + Runtime.getRuntime().addShutdownHook(new Thread(()->{ + run(new JMXExecutor()); + })); + } catch (InterruptedException e) { + fail("Interrupted while trying to block the finalizer thread", e); + } + } + + private static void blockFinalizerThread() throws InterruptedException { + System.out.println("trying to block the finalizer thread"); + o1 = new MyObject(); + o1 = null; + System.gc(); + finRunLatch.await(); + } + + private static void fail(String msg, Exception e) { + fail(msg); + e.printStackTrace(System.err); + } + + private static void fail(String msg) { + System.err.println(FAILED + ": " + msg); + } +} diff -r 32b706c7c6a0 -r 08f642d9214f hotspot/test/serviceability/dcmd/gc/RunFinalizationTest.java --- a/hotspot/test/serviceability/dcmd/gc/RunFinalizationTest.java Thu Oct 15 13:00:17 2015 +0200 +++ b/hotspot/test/serviceability/dcmd/gc/RunFinalizationTest.java Thu Oct 15 17:35:42 2015 +0200 @@ -21,13 +21,11 @@ * questions. */ -import java.util.concurrent.Phaser; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; +import java.util.ArrayList; +import java.util.List; -import jdk.test.lib.dcmd.CommandExecutor; -import jdk.test.lib.dcmd.JMXExecutor; -import jdk.test.lib.Utils; +import jdk.test.lib.OutputAnalyzer; +import jdk.test.lib.ProcessTools; /* * @test @@ -39,71 +37,21 @@ * jdk.jvmstat/sun.jvmstat.monitor * @build jdk.test.lib.* * @build jdk.test.lib.dcmd.* - * @run main/othervm RunFinalizationTest + * @build RunFinalizationTest FinalizationRunner + * @run main RunFinalizationTest */ public class RunFinalizationTest { - private static final long TIMEOUT = Utils.adjustTimeout(15000); // 15s - private static final Phaser ph = new Phaser(3); - static volatile boolean wasFinalized = false; - static volatile boolean wasInitialized = false; - - static class MyObject { - public MyObject() { - /* Make sure object allocation/deallocation is not optimized out */ - wasInitialized = true; - } - - protected void finalize() { - if (!Thread.currentThread().getName().equals("Finalizer")) { - wasFinalized = true; - ph.arrive(); - } else { - ph.arriveAndAwaitAdvance(); - } - } - } - - public static MyObject o; - - private static void run(CommandExecutor executor) { - o = new MyObject(); - o = null; - System.gc(); - executor.execute("GC.run_finalization"); - - System.out.println("Waiting for signal from finalizer"); + private final static String TEST_APP_NAME = "FinalizationRunner"; - long targetTime = System.currentTimeMillis() + TIMEOUT; - while (System.currentTimeMillis() < targetTime) { - try { - ph.awaitAdvanceInterruptibly(ph.arrive(), 200, TimeUnit.MILLISECONDS); - System.out.println("Received signal"); - break; - } catch (InterruptedException e) { - fail("Test error: Interrupted while waiting for signal from finalizer", e); - } catch (TimeoutException e) { - System.out.println("Haven't received signal in 200ms. Retrying ..."); - } - } + public static void main(String ... args) throws Exception { + List javaArgs = new ArrayList<>(); + javaArgs.add("-cp"); + javaArgs.add(System.getProperty("test.class.path")); + javaArgs.add(TEST_APP_NAME); + ProcessBuilder testAppPb = ProcessTools.createJavaProcessBuilder(javaArgs.toArray(new String[javaArgs.size()])); - if (!wasFinalized) { - fail("Test failure: Object was not finalized"); - } - } - - public static void main(String ... args) { - MyObject o = new MyObject(); - o = null; - Runtime.getRuntime().addShutdownHook(new Thread(()->{ - run(new JMXExecutor()); - })); - } - - private static void fail(String msg, Exception e) { - throw new Error(msg, e); - } - - private static void fail(String msg) { - throw new Error(msg); + OutputAnalyzer out = ProcessTools.executeProcess(testAppPb); + out.stderrShouldNotMatch("^" + FinalizationRunner.FAILED + ".*") + .stdoutShouldMatch("^" + FinalizationRunner.PASSED + ".*"); } }