1 /* 2 * Copyright (c) 2004, 2013, 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 * 28 * @build VMConnection RunToExit Exit0 29 * @run main/othervm RunToExit 30 */ 31 import java.io.InputStream; 32 import java.io.IOException; 33 import java.io.File; 34 import java.io.BufferedInputStream; 35 import java.net.ServerSocket; 36 import com.sun.jdi.Bootstrap; 37 import com.sun.jdi.VirtualMachine; 38 import com.sun.jdi.event.*; 39 import com.sun.jdi.connect.Connector; 40 import com.sun.jdi.connect.AttachingConnector; 41 import java.util.Map; 42 import java.util.List; 43 import java.util.Iterator; 44 45 public class RunToExit { 46 47 /* Increment this when ERROR: seen */ 48 static int error_seen = 0; 49 static volatile boolean ready = false; 50 /* 51 * Helper class to direct process output to a StringBuffer 52 */ 53 static class IOHandler implements Runnable { 54 private String name; 55 private BufferedInputStream in; 56 private StringBuffer buffer; 57 58 IOHandler(String name, InputStream in) { 59 this.name = name; 60 this.in = new BufferedInputStream(in); 61 this.buffer = new StringBuffer(); 62 } 63 64 static void handle(String name, InputStream in) { 65 IOHandler handler = new IOHandler(name, in); 66 Thread thr = new Thread(handler); 67 thr.setDaemon(true); 68 thr.start(); 69 } 70 71 public void run() { 72 try { 73 byte b[] = new byte[100]; 74 for (;;) { 75 int n = in.read(b, 0, 100); 76 // The first thing that will get read is 77 // Listening for transport dt_socket at address: xxxxx 78 // which shows the debuggee is ready to accept connections. 79 ready = true; 80 if (n < 0) { 81 break; 82 } 83 buffer.append(new String(b, 0, n)); 84 } 85 } catch (IOException ioe) { } 86 87 String str = buffer.toString(); 88 if ( str.contains("ERROR:") ) { 89 error_seen++; 90 } 91 System.out.println(name + ": " + str); 92 } 93 94 } 95 96 /* 97 * Find a connector by name 98 */ 99 private static Connector findConnector(String name) { 100 List connectors = Bootstrap.virtualMachineManager().allConnectors(); 101 Iterator iter = connectors.iterator(); 102 while (iter.hasNext()) { 103 Connector connector = (Connector)iter.next(); 104 if (connector.name().equals(name)) { 105 return connector; 106 } 107 } 108 return null; 109 } 110 111 /* 112 * Launch a server debuggee with the given address 113 */ 114 private static Process launch(String address, String class_name) throws IOException { 115 String exe = System.getProperty("java.home") 116 + File.separator + "bin" + File.separator + "java"; 117 String cmd = exe + " " + VMConnection.getDebuggeeVMOptions() + 118 " -agentlib:jdwp=transport=dt_socket" + 119 ",server=y" + ",suspend=y" + ",address=" + address + 120 " " + class_name; 121 122 System.out.println("Starting: " + cmd); 123 124 Process p = Runtime.getRuntime().exec(cmd); 125 126 IOHandler.handle("Input Stream", p.getInputStream()); 127 IOHandler.handle("Error Stream", p.getErrorStream()); 128 129 return p; 130 } 131 132 /* 133 * - pick a TCP port 134 * - Launch a server debuggee: server=y,suspend=y,address=${port} 135 * - run it to VM death 136 * - verify we saw no error 137 */ 138 public static void main(String args[]) throws Exception { 139 // find a free port 140 ServerSocket ss = new ServerSocket(0); 141 int port = ss.getLocalPort(); 142 ss.close(); 143 144 String address = String.valueOf(port); 145 146 // launch the server debuggee 147 Process process = launch(address, "Exit0"); 148 149 // wait for the debugge to be ready 150 while (!ready) { 151 try { 152 Thread.sleep(1000); 153 } catch(Exception ee) { 154 throw ee; 155 } 156 } 157 158 // attach to server debuggee and resume it so it can exit 159 AttachingConnector conn = (AttachingConnector)findConnector("com.sun.jdi.SocketAttach"); 160 Map conn_args = conn.defaultArguments(); 161 Connector.IntegerArgument port_arg = 162 (Connector.IntegerArgument)conn_args.get("port"); 163 port_arg.setValue(port); 164 VirtualMachine vm = conn.attach(conn_args); 165 166 // The first event is always a VMStartEvent, and it is always in 167 // an EventSet by itself. Wait for it. 168 EventSet evtSet = vm.eventQueue().remove(); 169 for (Event event: evtSet) { 170 if (event instanceof VMStartEvent) { 171 break; 172 } 173 throw new RuntimeException("Test failed - debuggee did not start properly"); 174 } 175 vm.eventRequestManager().deleteAllBreakpoints(); 176 vm.resume(); 177 178 int exitCode = process.waitFor(); 179 180 // if the server debuggee ran cleanly, we assume we were clean 181 if (exitCode == 0 && error_seen == 0) { 182 System.out.println("Test passed - server debuggee cleanly terminated"); 183 } else { 184 throw new RuntimeException("Test failed - server debuggee generated an error when it terminated"); 185 } 186 } 187 }