coleenp@3698: /* coleenp@3698: * Copyright 2012 SAP AG. All Rights Reserved. coleenp@3698: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. coleenp@3698: * coleenp@3698: * This code is free software; you can redistribute it and/or modify it coleenp@3698: * under the terms of the GNU General Public License version 2 only, as coleenp@3698: * published by the Free Software Foundation. coleenp@3698: * coleenp@3698: * This code is distributed in the hope that it will be useful, but WITHOUT coleenp@3698: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or coleenp@3698: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License coleenp@3698: * version 2 for more details (a copy is included in the LICENSE file that coleenp@3698: * accompanied this code). coleenp@3698: * coleenp@3698: * You should have received a copy of the GNU General Public License version coleenp@3698: * 2 along with this work; if not, write to the Free Software Foundation, coleenp@3698: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. coleenp@3698: * coleenp@3698: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA coleenp@3698: * or visit www.oracle.com if you need additional information or have any coleenp@3698: * questions. coleenp@3698: */ coleenp@3698: coleenp@3698: /* coleenp@3698: * @test FieldMonitor.java coleenp@3698: * @bug 7158988 ctornqvi@4519: * @key regression coleenp@3698: * @summary verify jvm does not crash while debugging ctornqvi@4519: * @run compile TestPostFieldModification.java ctornqvi@4519: * @run main/othervm FieldMonitor coleenp@3698: * @author axel.siebenborn@sap.com coleenp@3698: */ coleenp@3698: import java.io.BufferedReader; coleenp@3698: import java.io.IOException; coleenp@3698: import java.io.InputStream; coleenp@3698: import java.io.InputStreamReader; coleenp@3698: import java.io.OutputStream; coleenp@3698: import java.io.OutputStreamWriter; coleenp@3698: import java.io.Reader; coleenp@3698: import java.io.Writer; coleenp@3698: import java.util.Iterator; coleenp@3698: import java.util.List; coleenp@3698: import java.util.Map; coleenp@3698: coleenp@3698: import com.sun.jdi.Bootstrap; coleenp@3698: import com.sun.jdi.Field; coleenp@3698: import com.sun.jdi.ReferenceType; coleenp@3698: import com.sun.jdi.VirtualMachine; coleenp@3698: import com.sun.jdi.connect.Connector; coleenp@3698: import com.sun.jdi.connect.IllegalConnectorArgumentsException; coleenp@3698: import com.sun.jdi.connect.LaunchingConnector; coleenp@3698: import com.sun.jdi.connect.VMStartException; coleenp@3698: import com.sun.jdi.event.ClassPrepareEvent; coleenp@3698: import com.sun.jdi.event.Event; coleenp@3698: import com.sun.jdi.event.EventQueue; coleenp@3698: import com.sun.jdi.event.EventSet; coleenp@3698: import com.sun.jdi.event.ModificationWatchpointEvent; coleenp@3698: import com.sun.jdi.event.VMDeathEvent; coleenp@3698: import com.sun.jdi.event.VMDisconnectEvent; coleenp@3698: import com.sun.jdi.request.ClassPrepareRequest; coleenp@3698: import com.sun.jdi.request.EventRequest; coleenp@3698: import com.sun.jdi.request.EventRequestManager; coleenp@3698: import com.sun.jdi.request.ModificationWatchpointRequest; coleenp@3698: coleenp@3698: public class FieldMonitor { coleenp@3698: coleenp@3698: public static final String CLASS_NAME = "TestPostFieldModification"; coleenp@3698: public static final String FIELD_NAME = "value"; coleenp@3698: public static final String ARGUMENTS = "-Xshare:off -XX:+PrintGC"; coleenp@3698: coleenp@3698: public static void main(String[] args) coleenp@3698: throws IOException, InterruptedException { coleenp@3698: coleenp@3698: StringBuffer sb = new StringBuffer(); coleenp@3698: coleenp@3698: for (int i=0; i < args.length; i++) { coleenp@3698: sb.append(' '); coleenp@3698: sb.append(args[i]); coleenp@3698: } coleenp@3698: //VirtualMachine vm = launchTarget(sb.toString()); coleenp@3698: VirtualMachine vm = launchTarget(CLASS_NAME); coleenp@3698: coleenp@3698: System.out.println("Vm launched"); coleenp@3698: // set watch field on already loaded classes coleenp@3698: List referenceTypes = vm coleenp@3698: .classesByName(CLASS_NAME); coleenp@3698: for (ReferenceType refType : referenceTypes) { coleenp@3698: addFieldWatch(vm, refType); coleenp@3698: } coleenp@3698: // watch for loaded classes coleenp@3698: addClassWatch(vm); coleenp@3698: coleenp@3698: // process events coleenp@3698: EventQueue eventQueue = vm.eventQueue(); coleenp@3698: // resume the vm coleenp@3698: coleenp@3698: Process process = vm.process(); coleenp@3698: coleenp@3698: coleenp@3698: // Copy target's output and error to our output and error. coleenp@3698: Thread outThread = new StreamRedirectThread("out reader", process.getInputStream()); coleenp@3698: Thread errThread = new StreamRedirectThread("error reader", process.getErrorStream()); coleenp@3698: coleenp@3698: errThread.start(); coleenp@3698: outThread.start(); coleenp@3698: coleenp@3698: coleenp@3698: vm.resume(); coleenp@3698: boolean connected = true; coleenp@3698: while (connected) { coleenp@3698: EventSet eventSet = eventQueue.remove(); coleenp@3698: for (Event event : eventSet) { coleenp@3698: if (event instanceof VMDeathEvent coleenp@3698: || event instanceof VMDisconnectEvent) { coleenp@3698: // exit coleenp@3698: connected = false; coleenp@3698: } else if (event instanceof ClassPrepareEvent) { coleenp@3698: // watch field on loaded class coleenp@3698: System.out.println("ClassPrepareEvent"); coleenp@3698: ClassPrepareEvent classPrepEvent = (ClassPrepareEvent) event; coleenp@3698: ReferenceType refType = classPrepEvent coleenp@3698: .referenceType(); coleenp@3698: addFieldWatch(vm, refType); coleenp@3698: } else if (event instanceof ModificationWatchpointEvent) { coleenp@3698: System.out.println("sleep for 500 ms"); coleenp@3698: Thread.sleep(500); coleenp@3698: System.out.println("resume..."); coleenp@3698: coleenp@3698: ModificationWatchpointEvent modEvent = (ModificationWatchpointEvent) event; coleenp@3698: System.out.println("old=" coleenp@3698: + modEvent.valueCurrent()); coleenp@3698: System.out.println("new=" + modEvent.valueToBe()); coleenp@3698: System.out.println(); coleenp@3698: } coleenp@3698: } coleenp@3698: eventSet.resume(); coleenp@3698: } coleenp@3698: // Shutdown begins when event thread terminates coleenp@3698: try { coleenp@3698: errThread.join(); // Make sure output is forwarded coleenp@3698: outThread.join(); coleenp@3698: } catch (InterruptedException exc) { coleenp@3698: // we don't interrupt coleenp@3698: } coleenp@3698: } coleenp@3698: coleenp@3698: /** coleenp@3698: * Find a com.sun.jdi.CommandLineLaunch connector coleenp@3698: */ coleenp@3698: static LaunchingConnector findLaunchingConnector() { coleenp@3698: List connectors = Bootstrap.virtualMachineManager().allConnectors(); coleenp@3698: Iterator iter = connectors.iterator(); coleenp@3698: while (iter.hasNext()) { coleenp@3698: Connector connector = iter.next(); coleenp@3698: if (connector.name().equals("com.sun.jdi.CommandLineLaunch")) { coleenp@3698: return (LaunchingConnector)connector; coleenp@3698: } coleenp@3698: } coleenp@3698: throw new Error("No launching connector"); coleenp@3698: } coleenp@3698: /** coleenp@3698: * Return the launching connector's arguments. coleenp@3698: */ coleenp@3698: static Map connectorArguments(LaunchingConnector connector, String mainArgs) { coleenp@3698: Map arguments = connector.defaultArguments(); coleenp@3698: for (String key : arguments.keySet()) { coleenp@3698: System.out.println(key); coleenp@3698: } coleenp@3698: coleenp@3698: Connector.Argument mainArg = (Connector.Argument)arguments.get("main"); coleenp@3698: if (mainArg == null) { coleenp@3698: throw new Error("Bad launching connector"); coleenp@3698: } coleenp@3698: mainArg.setValue(mainArgs); coleenp@3698: coleenp@3698: Connector.Argument optionsArg = (Connector.Argument)arguments.get("options"); coleenp@3698: if (optionsArg == null) { coleenp@3698: throw new Error("Bad launching connector"); coleenp@3698: } coleenp@3698: optionsArg.setValue(ARGUMENTS); coleenp@3698: return arguments; coleenp@3698: } coleenp@3698: coleenp@3698: static VirtualMachine launchTarget(String mainArgs) { coleenp@3698: LaunchingConnector connector = findLaunchingConnector(); coleenp@3698: Map arguments = connectorArguments(connector, mainArgs); coleenp@3698: try { coleenp@3698: return (VirtualMachine) connector.launch(arguments); coleenp@3698: } catch (IOException exc) { coleenp@3698: throw new Error("Unable to launch target VM: " + exc); coleenp@3698: } catch (IllegalConnectorArgumentsException exc) { coleenp@3698: throw new Error("Internal error: " + exc); coleenp@3698: } catch (VMStartException exc) { coleenp@3698: throw new Error("Target VM failed to initialize: " + coleenp@3698: exc.getMessage()); coleenp@3698: } coleenp@3698: } coleenp@3698: coleenp@3698: coleenp@3698: private static void addClassWatch(VirtualMachine vm) { coleenp@3698: EventRequestManager erm = vm.eventRequestManager(); coleenp@3698: ClassPrepareRequest classPrepareRequest = erm coleenp@3698: .createClassPrepareRequest(); coleenp@3698: classPrepareRequest.addClassFilter(CLASS_NAME); coleenp@3698: classPrepareRequest.setEnabled(true); coleenp@3698: } coleenp@3698: coleenp@3698: coleenp@3698: private static void addFieldWatch(VirtualMachine vm, coleenp@3698: ReferenceType refType) { coleenp@3698: EventRequestManager erm = vm.eventRequestManager(); coleenp@3698: Field field = refType.fieldByName(FIELD_NAME); coleenp@3698: ModificationWatchpointRequest modificationWatchpointRequest = erm coleenp@3698: .createModificationWatchpointRequest(field); coleenp@3698: modificationWatchpointRequest.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); coleenp@3698: modificationWatchpointRequest.setEnabled(true); coleenp@3698: } coleenp@3698: } coleenp@3698: coleenp@3698: class StreamRedirectThread extends Thread { coleenp@3698: coleenp@3698: private final BufferedReader in; coleenp@3698: coleenp@3698: private static final int BUFFER_SIZE = 2048; coleenp@3698: coleenp@3698: /** coleenp@3698: * Set up for copy. coleenp@3698: * @param name Name of the thread coleenp@3698: * @param in Stream to copy from coleenp@3698: * @param out Stream to copy to coleenp@3698: */ coleenp@3698: StreamRedirectThread(String name, InputStream in) { coleenp@3698: super(name); coleenp@3698: this.in = new BufferedReader(new InputStreamReader(in)); coleenp@3698: } coleenp@3698: coleenp@3698: /** coleenp@3698: * Copy. coleenp@3698: */ coleenp@3698: public void run() { coleenp@3698: try { coleenp@3698: String line; coleenp@3698: while ((line = in.readLine ()) != null) { coleenp@3698: System.out.println ("testvm: " + line); coleenp@3698: } coleenp@3698: System.out.flush(); coleenp@3698: } catch(IOException exc) { coleenp@3698: System.err.println("Child I/O Transfer - " + exc); coleenp@3698: } coleenp@3698: } coleenp@3698: }