1 /* 2 * Copyright 2012 SAP AG. 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 /* 25 * @test FieldMonitor.java 26 * @bug 7158988 27 * @key regression 28 * @summary verify jvm does not crash while debugging 29 * @run compile TestPostFieldModification.java 30 * @run main/othervm FieldMonitor 31 * @author axel.siebenborn@sap.com 32 */ 33 import java.io.BufferedReader; 34 import java.io.IOException; 35 import java.io.InputStream; 36 import java.io.InputStreamReader; 37 import java.util.Iterator; 38 import java.util.List; 39 import java.util.Map; 40 41 import com.sun.jdi.Bootstrap; 42 import com.sun.jdi.Field; 43 import com.sun.jdi.ReferenceType; 44 import com.sun.jdi.VirtualMachine; 45 import com.sun.jdi.connect.Connector; 46 import com.sun.jdi.connect.IllegalConnectorArgumentsException; 47 import com.sun.jdi.connect.LaunchingConnector; 48 import com.sun.jdi.connect.VMStartException; 49 import com.sun.jdi.event.ClassPrepareEvent; 50 import com.sun.jdi.event.Event; 51 import com.sun.jdi.event.EventQueue; 52 import com.sun.jdi.event.EventSet; 53 import com.sun.jdi.event.ModificationWatchpointEvent; 54 import com.sun.jdi.event.VMDeathEvent; 55 import com.sun.jdi.event.VMStartEvent; 56 import com.sun.jdi.event.VMDisconnectEvent; 57 import com.sun.jdi.request.ClassPrepareRequest; 58 import com.sun.jdi.request.EventRequest; 59 import com.sun.jdi.request.EventRequestManager; 60 import com.sun.jdi.request.ModificationWatchpointRequest; 61 62 public class FieldMonitor { 63 64 public static final String CLASS_NAME = "TestPostFieldModification"; 65 public static final String FIELD_NAME = "value"; 66 public static final String ARGUMENTS = "-Xshare:off -XX:+PrintGC"; 67 68 public static void main(String[] args) 69 throws IOException, InterruptedException { 70 71 //VirtualMachine vm = launchTarget(sb.toString()); 72 VirtualMachine vm = launchTarget(CLASS_NAME); 73 74 System.out.println("Vm launched"); 75 76 // process events 77 EventQueue eventQueue = vm.eventQueue(); 78 // resume the vm 79 80 Process process = vm.process(); 81 82 83 // Copy target's output and error to our output and error. 84 Thread outThread = new StreamRedirectThread("out reader", process.getInputStream()); 85 Thread errThread = new StreamRedirectThread("error reader", process.getErrorStream()); 86 87 errThread.start(); 88 outThread.start(); 89 90 boolean connected = true; 91 int watched = 0; 92 while (connected) { 93 try { 94 EventSet eventSet = eventQueue.remove(); 95 for (Event event : eventSet) { 96 System.out.println("FieldMonitor-main receives: "+event); 97 if (event instanceof VMStartEvent) { 98 addClassWatch(vm); 99 } else if (event instanceof VMDeathEvent 100 || event instanceof VMDisconnectEvent) { 101 // exit 102 connected = false; 103 } else if (event instanceof ClassPrepareEvent) { 104 // watch field on loaded class 105 System.out.println("ClassPrepareEvent"); 106 ClassPrepareEvent classPrepEvent = (ClassPrepareEvent) event; 107 ReferenceType refType = classPrepEvent 108 .referenceType(); 109 addFieldWatch(vm, refType); 110 } else if (event instanceof ModificationWatchpointEvent) { 111 watched++; 112 System.out.println("sleep for 500 ms"); 113 Thread.sleep(500); 114 115 ModificationWatchpointEvent modEvent = (ModificationWatchpointEvent) event; 116 System.out.println("old=" 117 + modEvent.valueCurrent()); 118 System.out.println("new=" + modEvent.valueToBe()); 119 } 120 } 121 System.out.println("resume..."); 122 eventSet.resume(); 123 } catch (com.sun.jdi.VMDisconnectedException exc) { 124 // Guess this means it's not connected anymore, 125 // sometimes this happens and everything else hangs, just return. 126 return; 127 } 128 } 129 // Shutdown begins when event thread terminates 130 try { 131 errThread.join(); // Make sure output is forwarded 132 outThread.join(); 133 } catch (InterruptedException exc) { 134 // we don't interrupt 135 } 136 137 if (watched != 11) { // init + 10 modifications in TestPostFieldModification class 138 throw new Error("Expected to receive 11 times ModificationWatchpointEvent, but got "+watched); 139 } 140 } 141 142 /** 143 * Find a com.sun.jdi.CommandLineLaunch connector 144 */ 145 static LaunchingConnector findLaunchingConnector() { 146 List <Connector> connectors = Bootstrap.virtualMachineManager().allConnectors(); 147 Iterator <Connector> iter = connectors.iterator(); 148 while (iter.hasNext()) { 149 Connector connector = iter.next(); 150 if (connector.name().equals("com.sun.jdi.CommandLineLaunch")) { 151 return (LaunchingConnector)connector; 152 } 153 } 154 throw new Error("No launching connector"); 155 } 156 /** 157 * Return the launching connector's arguments. 158 */ 159 static Map <String,Connector.Argument> connectorArguments(LaunchingConnector connector, String mainArgs) { 160 Map<String,Connector.Argument> arguments = connector.defaultArguments(); 161 for (String key : arguments.keySet()) { 162 System.out.println(key); 163 } 164 165 Connector.Argument mainArg = (Connector.Argument)arguments.get("main"); 166 if (mainArg == null) { 167 throw new Error("Bad launching connector"); 168 } 169 mainArg.setValue(mainArgs); 170 171 Connector.Argument optionsArg = (Connector.Argument)arguments.get("options"); 172 if (optionsArg == null) { 173 throw new Error("Bad launching connector"); 174 } 175 optionsArg.setValue(ARGUMENTS); 176 return arguments; 177 } 178 179 static VirtualMachine launchTarget(String mainArgs) { 180 LaunchingConnector connector = findLaunchingConnector(); 181 Map arguments = connectorArguments(connector, mainArgs); 182 try { 183 return (VirtualMachine) connector.launch(arguments); 184 } catch (IOException exc) { 185 throw new Error("Unable to launch target VM: " + exc); 186 } catch (IllegalConnectorArgumentsException exc) { 187 throw new Error("Internal error: " + exc); 188 } catch (VMStartException exc) { 189 throw new Error("Target VM failed to initialize: " + 190 exc.getMessage()); 191 } 192 } 193 194 195 private static void addClassWatch(VirtualMachine vm) { 196 EventRequestManager erm = vm.eventRequestManager(); 197 ClassPrepareRequest classPrepareRequest = erm 198 .createClassPrepareRequest(); 199 classPrepareRequest.addClassFilter(CLASS_NAME); 200 classPrepareRequest.setEnabled(true); 201 } 202 203 204 private static void addFieldWatch(VirtualMachine vm, 205 ReferenceType refType) { 206 EventRequestManager erm = vm.eventRequestManager(); 207 Field field = refType.fieldByName(FIELD_NAME); 208 ModificationWatchpointRequest modificationWatchpointRequest = erm 209 .createModificationWatchpointRequest(field); 210 modificationWatchpointRequest.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); 211 modificationWatchpointRequest.setEnabled(true); 212 } 213 } 214 215 class StreamRedirectThread extends Thread { 216 217 private final BufferedReader in; 218 219 private static final int BUFFER_SIZE = 2048; 220 221 /** 222 * Set up for copy. 223 * @param name Name of the thread 224 * @param in Stream to copy from 225 * @param out Stream to copy to 226 */ 227 StreamRedirectThread(String name, InputStream in) { 228 super(name); 229 this.in = new BufferedReader(new InputStreamReader(in)); 230 } 231 232 /** 233 * Copy. 234 */ 235 public void run() { 236 try { 237 String line; 238 while ((line = in.readLine ()) != null) { 239 System.out.println ("testvm: " + line); 240 } 241 System.out.flush(); 242 } catch(IOException exc) { 243 System.err.println("Child I/O Transfer - " + exc); 244 } 245 } 246 }