1 /* 2 * Copyright (c) 2004, 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* @test 25 * @bug 4997445 26 * @summary Test that with server=y, when VM runs to System.exit() no error happens 27 * @library /test/lib 28 * @modules java.management 29 * jdk.jdi 30 * @build VMConnection RunToExit Exit0 31 * @run driver RunToExit 32 */ 33 import com.sun.jdi.Bootstrap; 34 import com.sun.jdi.VirtualMachine; 35 import com.sun.jdi.event.*; 36 import com.sun.jdi.connect.Connector; 37 import com.sun.jdi.connect.AttachingConnector; 38 import java.net.ConnectException; 39 import java.util.Map; 40 import java.util.List; 41 import java.util.Iterator; 42 import java.util.concurrent.TimeUnit; 43 import java.util.regex.Matcher; 44 import java.util.regex.Pattern; 45 import java.util.stream.Collectors; 46 import jdk.test.lib.process.ProcessTools; 47 48 public class RunToExit { 49 50 /* Increment this when ERROR: seen */ 51 static volatile int error_seen = 0; 52 static volatile boolean ready = false; 53 54 /* port the debuggee is listening on */ 55 private static String address; 56 57 /* 58 * Find a connector by name 59 */ findConnector(String name)60 private static Connector findConnector(String name) { 61 List connectors = Bootstrap.virtualMachineManager().allConnectors(); 62 Iterator iter = connectors.iterator(); 63 while (iter.hasNext()) { 64 Connector connector = (Connector)iter.next(); 65 if (connector.name().equals(name)) { 66 return connector; 67 } 68 } 69 return null; 70 } 71 72 /* 73 * Launch a server debuggee, detect debuggee listening port 74 */ launch(String class_name)75 private static Process launch(String class_name) throws Exception { 76 String args[] = new String[]{ 77 "-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=0", 78 class_name 79 }; 80 args = VMConnection.insertDebuggeeVMOptions(args); 81 82 ProcessBuilder launcher = ProcessTools.createJavaProcessBuilder(args); 83 84 System.out.println(launcher.command().stream().collect(Collectors.joining(" ", "Starting: ", ""))); 85 86 Process p = ProcessTools.startProcess( 87 class_name, 88 launcher, 89 RunToExit::checkForError, 90 RunToExit::isTransportListening, 91 0, 92 TimeUnit.NANOSECONDS 93 ); 94 95 return p; 96 } 97 98 /* warm-up predicate for debuggee */ 99 private static Pattern listenRegexp = Pattern.compile("Listening for transport \\b(.+)\\b at address: \\b(.+)\\b"); 100 isTransportListening(String line)101 private static boolean isTransportListening(String line) { 102 Matcher m = listenRegexp.matcher(line); 103 if (!m.matches()) { 104 return false; 105 } 106 // address is 2nd group 107 address = m.group(2); 108 return true; 109 } 110 checkForError(String line)111 private static void checkForError(String line) { 112 if (line.contains("ERROR:")) { 113 error_seen++; 114 } 115 } 116 117 /* 118 * - Launch a server debuggee: server=y,suspend=y,address=0 119 * - detect the port debuggee is listening on 120 * - run it to VM death 121 * - verify we saw no error 122 */ main(String args[])123 public static void main(String args[]) throws Exception { 124 // launch the server debuggee 125 Process process = launch("Exit0"); 126 127 // attach to server debuggee and resume it so it can exit 128 AttachingConnector conn = (AttachingConnector)findConnector("com.sun.jdi.SocketAttach"); 129 Map conn_args = conn.defaultArguments(); 130 Connector.IntegerArgument port_arg = 131 (Connector.IntegerArgument)conn_args.get("port"); 132 port_arg.setValue(address); 133 134 System.out.println("Connection arguments: " + conn_args); 135 136 VirtualMachine vm = null; 137 while (vm == null) { 138 try { 139 vm = conn.attach(conn_args); 140 } catch (ConnectException e) { 141 e.printStackTrace(System.out); 142 System.out.println("--- Debugee not ready. Retrying in 500ms. ---"); 143 Thread.sleep(500); 144 } 145 } 146 147 // The first event is always a VMStartEvent, and it is always in 148 // an EventSet by itself. Wait for it. 149 EventSet evtSet = vm.eventQueue().remove(); 150 for (Event event: evtSet) { 151 if (event instanceof VMStartEvent) { 152 break; 153 } 154 throw new RuntimeException("Test failed - debuggee did not start properly"); 155 } 156 vm.eventRequestManager().deleteAllBreakpoints(); 157 vm.resume(); 158 159 int exitCode = process.waitFor(); 160 161 // if the server debuggee ran cleanly, we assume we were clean 162 if (exitCode == 0 && error_seen == 0) { 163 System.out.println("Test passed - server debuggee cleanly terminated"); 164 } else { 165 throw new RuntimeException("Test failed - server debuggee generated an error when it terminated, " + 166 "exit code was " + exitCode + ", " + error_seen + " error(s) seen in debugee output."); 167 } 168 } 169 } 170