# HG changeset patch # User ddehaven # Date 1422461658 28800 # Node ID 884fc5070548789904e4dadca95759091401bbe5 # Parent 86a1284f1128036ed4c65823435f4e02d836bf40# Parent 42f73a4a323bdf455f0263739f4eaa55d02be80e Merge diff -r 86a1284f1128 -r 884fc5070548 jdk/src/java.base/share/classes/sun/misc/Unsafe.java --- a/jdk/src/java.base/share/classes/sun/misc/Unsafe.java Tue Jan 27 09:32:45 2015 -0800 +++ b/jdk/src/java.base/share/classes/sun/misc/Unsafe.java Wed Jan 28 08:14:18 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -845,22 +845,6 @@ public native Object allocateInstance(Class cls) throws InstantiationException; - /** Lock the object. It must get unlocked via {@link #monitorExit}. */ - public native void monitorEnter(Object o); - - /** - * Unlock the object. It must have been locked via {@link - * #monitorEnter}. - */ - public native void monitorExit(Object o); - - /** - * Tries to lock the object. Returns true or false to indicate - * whether the lock succeeded. If it did, the object must be - * unlocked via {@link #monitorExit}. - */ - public native boolean tryMonitorEnter(Object o); - /** Throw the exception without telling the verifier. */ public native void throwException(Throwable ee); diff -r 86a1284f1128 -r 884fc5070548 jdk/test/ProblemList.txt --- a/jdk/test/ProblemList.txt Tue Jan 27 09:32:45 2015 -0800 +++ b/jdk/test/ProblemList.txt Wed Jan 28 08:14:18 2015 -0800 @@ -128,9 +128,6 @@ # jdk_instrument -# 8058536 -java/lang/instrument/NativeMethodPrefixAgent.java generic-all - # 8061177 java/lang/instrument/RedefineBigClass.sh generic-all java/lang/instrument/RetransformBigClass.sh generic-all diff -r 86a1284f1128 -r 884fc5070548 jdk/test/java/lang/ProcessBuilder/Basic.java --- a/jdk/test/java/lang/ProcessBuilder/Basic.java Tue Jan 27 09:32:45 2015 -0800 +++ b/jdk/test/java/lang/ProcessBuilder/Basic.java Wed Jan 28 08:14:18 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -26,7 +26,7 @@ * @bug 4199068 4738465 4937983 4930681 4926230 4931433 4932663 4986689 * 5026830 5023243 5070673 4052517 4811767 6192449 6397034 6413313 * 6464154 6523983 6206031 4960438 6631352 6631966 6850957 6850958 - * 4947220 7018606 7034570 4244896 5049299 8003488 + * 4947220 7018606 7034570 4244896 5049299 8003488 8054494 * @summary Basic tests for Process and Environment Variable code * @run main/othervm/timeout=300 Basic * @run main/othervm/timeout=300 -Djdk.lang.Process.launchMechanism=fork Basic @@ -2059,13 +2059,11 @@ Thread.yield(); } } else if (s instanceof BufferedInputStream) { - Field f = Unsafe.class.getDeclaredField("theUnsafe"); - f.setAccessible(true); - Unsafe unsafe = (Unsafe)f.get(null); - - while (unsafe.tryMonitorEnter(s)) { - unsafe.monitorExit(s); - Thread.sleep(1); + // Wait until after the s.read occurs in "thread" by + // checking when the input stream monitor is acquired + // (BufferedInputStream.read is synchronized) + while (!isLocked(s, 10)) { + Thread.sleep(100); } } p.destroy(); @@ -2565,4 +2563,21 @@ catch (Throwable t) { if (k.isAssignableFrom(t.getClass())) pass(); else unexpected(t);}} + + static boolean isLocked(final Object monitor, final long millis) throws InterruptedException { + return new Thread() { + volatile boolean unlocked; + + @Override + public void run() { + synchronized (monitor) { unlocked = true; } + } + + boolean isLocked() throws InterruptedException { + start(); + join(millis); + return !unlocked; + } + }.isLocked(); + } } diff -r 86a1284f1128 -r 884fc5070548 jdk/test/java/lang/ref/OOMEInReferenceHandler.java --- a/jdk/test/java/lang/ref/OOMEInReferenceHandler.java Tue Jan 27 09:32:45 2015 -0800 +++ b/jdk/test/java/lang/ref/OOMEInReferenceHandler.java Wed Jan 28 08:14:18 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2014, 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 @@ -25,7 +25,7 @@ * @test * @bug 7038914 8016341 * @summary Verify that the reference handler does not die after an OOME allocating the InterruptedException object - * @run main/othervm -Xmx24M -XX:-UseTLAB OOMEInReferenceHandler + * @run main/othervm -XX:-UseGCOverheadLimit -Xmx24M -XX:-UseTLAB OOMEInReferenceHandler * @author peter.levart@gmail.com */ diff -r 86a1284f1128 -r 884fc5070548 jdk/test/sun/tools/jmap/heapconfig/JMapHeapConfigTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/sun/tools/jmap/heapconfig/JMapHeapConfigTest.java Wed Jan 28 08:14:18 2015 -0800 @@ -0,0 +1,132 @@ +/* + * 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. + */ + +/* + * @test + * @bug 8042397 + * @summary Unit test for jmap utility test heap configuration reader + * @library /lib/testlibrary + * @build jdk.testlibrary.* + * @build JMapHeapConfigTest LingeredApp TmtoolTestScenario + * @run main JMapHeapConfigTest + */ +import java.io.IOException; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import jdk.testlibrary.Utils; + +public class JMapHeapConfigTest { + + static final String expectedJMapValues[] = { + "MinHeapFreeRatio", + "MaxHeapFreeRatio", + "MaxHeapSize", + "NewSize", + "MaxNewSize", + "OldSize", + "NewRatio", + "SurvivorRatio", + "MetaspaceSize", + "CompressedClassSpaceSize", + "G1HeapRegionSize"}; + + // ignoring MaxMetaspaceSize + + private static Map parseJMapOutput(List jmapOutput) { + Map heapConfigMap = new HashMap(); + boolean shouldParse = false; + + for (String line : jmapOutput) { + line = line.trim(); + + if (line.startsWith("Heap Configuration:")) { + shouldParse = true; + continue; + } + + if (line.startsWith("Heap Usage:")) { + shouldParse = false; + continue; + } + + if (shouldParse && !line.equals("")) { + String[] lv = line.split("\\s+"); + try { + heapConfigMap.put(lv[0], lv[2]); + } catch (ArrayIndexOutOfBoundsException ex) { + // Ignore mailformed lines + } + } + } + return heapConfigMap; + } + + // Compare stored values + private static void compareValues(Map parsedJMapOutput, Map parsedVmOutput) { + for (String key : expectedJMapValues) { + try { + String jmapVal = parsedJMapOutput.get(key); + if (jmapVal == null) { + throw new RuntimeException("Key '" + key + "' doesn't exists in jmap output"); + } + + String vmVal = parsedVmOutput.get(key); + if (vmVal == null) { + throw new RuntimeException("Key '" + key + "' doesn't exists in vm output"); + } + + if (new BigDecimal(jmapVal).compareTo(new BigDecimal(vmVal)) != 0) { + throw new RuntimeException(String.format("Key %s doesn't match %s vs %s", key, vmVal, jmapVal)); + } + } catch (NumberFormatException ex) { + throw new RuntimeException("Unexpected key '" + key + "' value", ex); + } + } + } + + public static void main(String[] args) { + System.out.println("Starting JMapHeapConfigTest"); + + // Forward vm options to LingeredApp + ArrayList cmd = new ArrayList(); + cmd.addAll(Utils.getVmOptions()); + cmd.add("-XX:+PrintFlagsFinal"); + + TmtoolTestScenario tmt = TmtoolTestScenario.create("jmap", "-heap"); + int exitcode = tmt.launch(cmd); + if (exitcode != 0) { + throw new RuntimeException("Test FAILED jmap exits with non zero exit code " + exitcode); + } + + Map parsedJmapOutput = parseJMapOutput(tmt.getToolOutput()); + Map parsedVMOutput = tmt.parseFlagsFinal(); + + compareValues(parsedJmapOutput, parsedVMOutput); + + // If test fails it throws RuntimeException + System.out.println("Test PASSED"); + } +} diff -r 86a1284f1128 -r 884fc5070548 jdk/test/sun/tools/jmap/heapconfig/LingeredApp.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/sun/tools/jmap/heapconfig/LingeredApp.java Wed Jan 28 08:14:18 2015 -0800 @@ -0,0 +1,402 @@ +/* + * 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.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.file.Files; +import java.nio.file.NoSuchFileException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.attribute.FileTime; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +/** + * This is a framework to launch an app that could be synchronized with caller + * to make further attach actions reliable across supported platforms + + * Caller example: + * SmartTestApp a = SmartTestApp.startApp(cmd); + * // do something + * a.stopApp(); + * + * or fine grained control + * + * a = new SmartTestApp("MyLock.lck"); + * a.createLock(); + * a.runApp(); + * a.waitAppReady(); + * // do something + * a.deleteLock(); + * a.waitAppTerminate(); + * + * Then you can work with app output and process object + * + * output = a.getAppOutput(); + * process = a.getProcess(); + * + */ +public class LingeredApp { + + private static final long spinDelay = 1000; + + private final String lockFileName; + private long lockCreationTime; + private Process appProcess; + private final ArrayList storedAppOutput; + + /* + * Drain child process output, store it into string array + */ + class InputGobbler extends Thread { + + InputStream is; + List astr; + + InputGobbler(InputStream is, List astr) { + this.is = is; + this.astr = astr; + } + + public void run() { + try { + InputStreamReader isr = new InputStreamReader(is); + BufferedReader br = new BufferedReader(isr); + String line = null; + while ((line = br.readLine()) != null) { + astr.add(line); + } + } catch (IOException ex) { + // pass + } + } + } + + /** + * Create LingeredApp object on caller side. Lock file have be a valid filename + * at writable location + * + * @param lockFileName - the name of lock file + */ + public LingeredApp(String lockFileName) { + this.lockFileName = lockFileName; + this.storedAppOutput = new ArrayList(); + } + + /** + * + * @return name of lock file + */ + public String getLockFileName() { + return this.lockFileName; + } + + /** + * + * @return name of testapp + */ + public String getAppName() { + return this.getClass().getName(); + } + + /** + * + * @return pid of java process running testapp + */ + public long getPid() { + if (appProcess == null) { + throw new RuntimeException("Process is not alive"); + } + return appProcess.getPid(); + } + + /** + * + * @return process object + */ + public Process getProcess() { + return appProcess; + } + + /** + * + * @return application output as string array. Empty array if application produced no output + */ + List getAppOutput() { + if (appProcess.isAlive()) { + throw new RuntimeException("Process is still alive. Can't get its output."); + } + return storedAppOutput; + } + + /* Make sure all part of the app use the same method to get dates, + as different methods could produce different results + */ + private static long epoch() { + return new Date().getTime(); + } + + private static long lastModified(String fileName) throws IOException { + Path path = Paths.get(fileName); + BasicFileAttributes attr = Files.readAttributes(path, BasicFileAttributes.class); + return attr.lastModifiedTime().toMillis(); + } + + private static void setLastModified(String fileName, long newTime) throws IOException { + Path path = Paths.get(fileName); + FileTime fileTime = FileTime.fromMillis(newTime); + Files.setLastModifiedTime(path, fileTime); + } + + /** + * create lock + * + * @throws IOException + */ + public void createLock() throws IOException { + Path path = Paths.get(lockFileName); + // Files.deleteIfExists(path); + Files.createFile(path); + lockCreationTime = lastModified(lockFileName); + } + + /** + * Delete lock + * + * @throws IOException + */ + public void deleteLock() throws IOException { + try { + Path path = Paths.get(lockFileName); + Files.delete(path); + } catch (NoSuchFileException ex) { + // Lock already deleted. Ignore error + } + } + + public void waitAppTerminate() { + while (true) { + try { + appProcess.waitFor(); + break; + } catch (InterruptedException ex) { + // pass + } + } + } + + /** + * The app touches the lock file when it's started + * wait while it happens. Caller have to delete lock on wait error. + * + * @param timeout + * @throws java.io.IOException + */ + public void waitAppReady(long timeout) throws IOException { + long here = epoch(); + while (true) { + long epoch = epoch(); + if (epoch - here > (timeout * 1000)) { + throw new IOException("App waiting timeout"); + } + + // Live process should touch lock file every second + long lm = lastModified(lockFileName); + if (lm > lockCreationTime) { + break; + } + + // Make sure process didn't already exit + if (!appProcess.isAlive()) { + throw new IOException("App exited unexpectedly with " + appProcess.exitValue()); + } + + try { + Thread.sleep(spinDelay); + } catch (InterruptedException ex) { + // pass + } + } + } + + /** + * Run the app + * + * @param vmArguments + * @throws IOException + */ + public void runApp(List vmArguments) + throws IOException { + + // We should always use testjava or throw an exception, + // so we can't use JDKToolFinder.getJDKTool("java"); + // that falls back to compile java on error + String jdkPath = System.getProperty("test.jdk"); + if (jdkPath == null) { + // we are not under jtreg, try env + Map env = System.getenv(); + jdkPath = env.get("TESTJAVA"); + } + + if (jdkPath == null) { + throw new RuntimeException("Can't determine jdk path neither test.jdk property no TESTJAVA env are set"); + } + + String osname = System.getProperty("os.name"); + String javapath = jdkPath + ((osname.startsWith("window")) ? "/bin/java.exe" : "/bin/java"); + + List cmd = new ArrayList(); + cmd.add(javapath); + + + if (vmArguments == null) { + // Propagate test.vm.options to LingeredApp, filter out possible empty options + String testVmOpts[] = System.getProperty("test.vm.opts","").split("\\s+"); + for (String s : testVmOpts) { + if (!s.equals("")) { + cmd.add(s); + } + } + } + else{ + // Lets user manage LingerApp options + cmd.addAll(vmArguments); + } + + // Make sure we set correct classpath to run the app + cmd.add("-cp"); + String classpath = System.getProperty("test.class.path"); + cmd.add((classpath == null) ? "." : classpath); + + cmd.add(this.getAppName()); + cmd.add(lockFileName); + + // Reporting + StringBuilder cmdLine = new StringBuilder(); + for (String strCmd : cmd) { + cmdLine.append("'").append(strCmd).append("' "); + } + + // A bit of verbosity + System.out.println("Command line: [" + cmdLine.toString() + "]"); + + ProcessBuilder pb = new ProcessBuilder(cmd); + // we don't expect any error output but make sure we are not stuck on pipe + // pb.redirectErrorStream(false); + pb.redirectError(ProcessBuilder.Redirect.INHERIT); + + appProcess = pb.start(); + + // Create pipe reader for process, and read stdin and stderr to array of strings + InputGobbler gb = new InputGobbler(appProcess.getInputStream(), storedAppOutput); + gb.start(); + } + + /** + * High level interface for test writers + */ + /** + * Factory method that creates SmartAppTest object with ready to use application + * lock name is autogenerated, wait timeout is hardcoded + * @param cmd - vm options, could be null to auto add testvm.options + * @return LingeredApp object + * @throws IOException + */ + public static LingeredApp startApp(List cmd) throws IOException { + final String lockName = UUID.randomUUID().toString() + ".lck"; + final int waitTime = 10; + + LingeredApp a = new LingeredApp(lockName); + a.createLock(); + try { + a.runApp(cmd); + a.waitAppReady(waitTime); + } catch (Exception ex) { + a.deleteLock(); + throw ex; + } + + return a; + } + + public static LingeredApp startApp() throws IOException { + return startApp(null); + } + + /** + * Delete lock file that signal app to terminate, then + * waits until app is actually terminated. + * @throws IOException + */ + public void stopApp() throws IOException { + deleteLock(); + waitAppTerminate(); + int exitcode = appProcess.exitValue(); + if (exitcode != 0) { + throw new IOException("LingeredApp terminated with non-zero exit code " + exitcode); + } + } + + /** + * This part is the application it self + */ + public static void main(String args[]) { + + if (args.length != 1) { + System.err.println("Lock file name is not specified"); + System.exit(7); + } + + String theLockFileName = args[0]; + + try { + Path path = Paths.get(theLockFileName); + + while (Files.exists(path)) { + long lm = lastModified(theLockFileName); + long now = epoch(); + + // A bit of paranoja, don't allow test app to run more than an hour + if (now - lm > 3600) { + throw new IOException("Lock is too old. Aborting"); + } + + // Touch lock to indicate our rediness + setLastModified(theLockFileName, now); + Thread.sleep(spinDelay); + } + + } catch (Exception ex) { + System.err.println("LingeredApp ERROR: " + ex); + // Leave exit_code = 1 to Java launcher + System.exit(3); + } + + System.exit(0); + } +} diff -r 86a1284f1128 -r 884fc5070548 jdk/test/sun/tools/jmap/heapconfig/LingeredAppTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/sun/tools/jmap/heapconfig/LingeredAppTest.java Wed Jan 28 08:14:18 2015 -0800 @@ -0,0 +1,72 @@ +/* + * 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. + */ + +/* + * @test + * @summary Unit test for LingeredApp + * @compile LingeredAppTest.java + * @compile LingeredApp.java + * @run main LingeredAppTest + */ +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.logging.Level; +import java.util.logging.Logger; + +public class LingeredAppTest { + + public static void main(String[] args) { + try { + System.out.println("Starting LingeredApp with default parameters"); + + ArrayList cmd = new ArrayList(); + + // Propagate test.vm.options to LingeredApp, filter out possible empty options + String testVmOpts[] = System.getProperty("test.vm.opts","").split("\\s+"); + for (String s : testVmOpts) { + if (!s.equals("")) { + cmd.add(s); + } + } + + cmd.add("-XX:+PrintFlagsFinal"); + + LingeredApp a = LingeredApp.startApp(cmd); + System.out.printf("App pid: %d\n", a.getPid()); + a.stopApp(); + + System.out.println("App output:"); + int count = 0; + for (String line : a.getAppOutput()) { + count += 1; + } + System.out.println("Found " + count + " lines in VM output"); + System.out.println("Test PASSED"); + } catch (IOException ex) { + ex.printStackTrace(); + System.out.println("Test ERROR"); + System.exit(3); + } + } +} diff -r 86a1284f1128 -r 884fc5070548 jdk/test/sun/tools/jmap/heapconfig/TmtoolTestScenario.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/sun/tools/jmap/heapconfig/TmtoolTestScenario.java Wed Jan 28 08:14:18 2015 -0800 @@ -0,0 +1,137 @@ +/* + * 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.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; +import jdk.testlibrary.JDKToolLauncher; +import jdk.testlibrary.Utils; + +public class TmtoolTestScenario { + + private final ArrayList toolOutput = new ArrayList(); + private LingeredApp theApp = null; + private final String toolName; + private final String[] toolArgs; + + /** + * @param toolName - name of tool to test + * @param toolArgs - tool arguments + * @return the object + */ + public static TmtoolTestScenario create(String toolName, String... toolArgs) { + return new TmtoolTestScenario(toolName, toolArgs); + } + + /** + * @return STDOUT of tool + */ + public List getToolOutput() { + return toolOutput; + } + + /** + * + * @return STDOUT of test app + */ + public List getAppOutput() { + return theApp.getAppOutput(); + } + + /** + * @return Value of the app output with -XX:+PrintFlagsFinal as a map. + */ + public Map parseFlagsFinal() { + List astr = theApp.getAppOutput(); + Map vmMap = new HashMap(); + + for (String line : astr) { + String[] lv = line.trim().split("\\s+"); + try { + vmMap.put(lv[1], lv[3]); + } catch (ArrayIndexOutOfBoundsException ex) { + // ignore mailformed lines + } + } + return vmMap; + } + + /** + * + * @param vmArgs - vm and java arguments to launch test app + * @return exit code of tool + */ + public int launch(List vmArgs) { + System.out.println("Starting LingeredApp"); + try { + try { + theApp = LingeredApp.startApp(vmArgs); + + System.out.println("Starting " + toolName + " against " + theApp.getPid()); + JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK(toolName); + + for (String cmd : toolArgs) { + launcher.addToolArg(cmd); + } + launcher.addToolArg(Long.toString(theApp.getPid())); + + ProcessBuilder processBuilder = new ProcessBuilder(launcher.getCommand()); + processBuilder.redirectError(ProcessBuilder.Redirect.INHERIT); + Process toolProcess = processBuilder.start(); + + // By default child process output stream redirected to pipe, so we are reading it in foreground. + BufferedReader reader = new BufferedReader(new InputStreamReader(toolProcess.getInputStream())); + + String line; + while ((line = reader.readLine()) != null) { + toolOutput.add(line.trim()); + } + + toolProcess.waitFor(); + + return toolProcess.exitValue(); + } finally { + theApp.stopApp(); + } + } catch (IOException | InterruptedException ex) { + throw new RuntimeException("Test ERROR " + ex, ex); + } + } + + public void launch(String... appArgs) throws IOException { + launch(Arrays.asList(appArgs)); + } + + private TmtoolTestScenario(String toolName, String[] toolArgs) { + this.toolName = toolName; + this.toolArgs = toolArgs; + } + +}