1 /* 2 * Copyright (c) 2014 SAP SE. 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 import java.io.BufferedReader; 25 import java.io.IOException; 26 import java.io.InputStream; 27 import java.io.InputStreamReader; 28 import java.util.Iterator; 29 import java.util.List; 30 import java.util.Map; 31 32 import com.sun.jdi.AbsentInformationException; 33 import com.sun.jdi.Bootstrap; 34 import com.sun.jdi.LocalVariable; 35 import com.sun.jdi.Location; 36 import com.sun.jdi.ObjectReference; 37 import com.sun.jdi.ReferenceType; 38 import com.sun.jdi.StackFrame; 39 import com.sun.jdi.ThreadReference; 40 import com.sun.jdi.Value; 41 import com.sun.jdi.VirtualMachine; 42 import com.sun.jdi.connect.Connector; 43 import com.sun.jdi.connect.Connector.Argument; 44 import com.sun.jdi.connect.IllegalConnectorArgumentsException; 45 import com.sun.jdi.connect.LaunchingConnector; 46 import com.sun.jdi.connect.VMStartException; 47 import com.sun.jdi.event.BreakpointEvent; 48 import com.sun.jdi.event.ClassPrepareEvent; 49 import com.sun.jdi.event.Event; 50 import com.sun.jdi.event.EventQueue; 51 import com.sun.jdi.event.EventSet; 52 import com.sun.jdi.event.VMDeathEvent; 53 import com.sun.jdi.event.VMDisconnectEvent; 54 import com.sun.jdi.event.VMStartEvent; 55 import com.sun.jdi.request.BreakpointRequest; 56 import com.sun.jdi.request.ClassPrepareRequest; 57 import com.sun.jdi.request.EventRequestManager; 58 59 60 /* 61 * @test GetObjectLockCount.java 62 * @bug 8036666 63 * @key regression 64 * @summary verify jvm returns correct lock recursion count 65 * @run compile -g RecursiveObjectLock.java 66 * @run main/othervm GetObjectLockCount 67 * @author axel.siebenborn@sap.com 68 */ 69 70 public class GetObjectLockCount { 71 72 public static final String CLASS_NAME = "RecursiveObjectLock"; 73 public static final String METHOD_NAME = "breakpoint1"; 74 public static final String ARGUMENTS = ""; 75 76 77 /** 78 * Find a com.sun.jdi.CommandLineLaunch connector 79 */ 80 static LaunchingConnector findLaunchingConnector() { 81 List <Connector> connectors = Bootstrap.virtualMachineManager().allConnectors(); 82 Iterator <Connector> iter = connectors.iterator(); 83 while (iter.hasNext()) { 84 Connector connector = iter.next(); 85 if (connector.name().equals("com.sun.jdi.CommandLineLaunch")) { 86 return (LaunchingConnector)connector; 87 } 88 } 89 throw new Error("No launching connector"); 90 } 91 92 static VirtualMachine launchTarget(String mainArgs) { 93 LaunchingConnector connector = findLaunchingConnector(); 94 Map<String, Argument> arguments = connectorArguments(connector, mainArgs); 95 try { 96 return (VirtualMachine) connector.launch(arguments); 97 } catch (IOException exc) { 98 throw new Error("Unable to launch target VM: " + exc); 99 } catch (IllegalConnectorArgumentsException exc) { 100 throw new Error("Internal error: " + exc); 101 } catch (VMStartException exc) { 102 throw new Error("Target VM failed to initialize: " + 103 exc.getMessage()); 104 } 105 } 106 /** 107 * Return the launching connector's arguments. 108 */ 109 static Map <String,Connector.Argument> connectorArguments(LaunchingConnector connector, String mainArgs) { 110 Map<String,Connector.Argument> arguments = connector.defaultArguments(); 111 112 Connector.Argument mainArg = (Connector.Argument)arguments.get("main"); 113 if (mainArg == null) { 114 throw new Error("Bad launching connector"); 115 } 116 mainArg.setValue(mainArgs); 117 118 Connector.Argument optionsArg = (Connector.Argument)arguments.get("options"); 119 if (optionsArg == null) { 120 throw new Error("Bad launching connector"); 121 } 122 optionsArg.setValue(ARGUMENTS); 123 return arguments; 124 } 125 126 private static void addClassWatch(VirtualMachine vm) { 127 EventRequestManager erm = vm.eventRequestManager(); 128 ClassPrepareRequest classPrepareRequest = erm 129 .createClassPrepareRequest(); 130 classPrepareRequest.addClassFilter(CLASS_NAME); 131 classPrepareRequest.setEnabled(true); 132 } 133 134 private static void addBreakpoint(VirtualMachine vm, ReferenceType refType) { 135 Location breakpointLocation = null; 136 List<Location> locs; 137 try { 138 locs = refType.allLineLocations(); 139 for (Location loc: locs) { 140 if (loc.method().name().equals(METHOD_NAME)) { 141 breakpointLocation = loc; 142 break; 143 } 144 } 145 } catch (AbsentInformationException e) { 146 // TODO Auto-generated catch block 147 e.printStackTrace(); 148 } 149 if (breakpointLocation != null) { 150 EventRequestManager evtReqMgr = vm.eventRequestManager(); 151 BreakpointRequest bReq = evtReqMgr.createBreakpointRequest(breakpointLocation); 152 bReq.setSuspendPolicy(BreakpointRequest.SUSPEND_ALL); 153 bReq.enable(); 154 } 155 } 156 157 /** 158 * @param args 159 * @throws InterruptedException 160 */ 161 public static void main(String[] args) throws InterruptedException { 162 163 VirtualMachine vm = launchTarget(CLASS_NAME); 164 165 // process events 166 EventQueue eventQueue = vm.eventQueue(); 167 // resume the vm 168 boolean launched = false; 169 170 while (!launched) { 171 EventSet eventSet = eventQueue.remove(); 172 for (Event event : eventSet) { 173 if (event instanceof VMStartEvent) { 174 System.out.println("Vm launched"); 175 // set watch field on already loaded classes 176 List<ReferenceType> referenceTypes = vm.classesByName(CLASS_NAME); 177 for (ReferenceType refType : referenceTypes) { 178 System.out.println("Found Class"); 179 addBreakpoint(vm, refType); 180 } 181 182 // watch for loaded classes 183 addClassWatch(vm); 184 vm.resume(); 185 launched = true; 186 } 187 } 188 } 189 190 Process process = vm.process(); 191 192 // Copy target's output and error to our output and error. 193 Thread outThread = new StreamRedirectThread("out reader", process.getInputStream()); 194 Thread errThread = new StreamRedirectThread("error reader", process.getErrorStream()); 195 196 int recursionCount = -1; 197 198 errThread.start(); 199 outThread.start(); 200 boolean connected = true; 201 while (connected) { 202 EventSet eventSet = eventQueue.remove(); 203 for (Event event : eventSet) { 204 if (event instanceof VMDeathEvent || event instanceof VMDisconnectEvent) { 205 // exit 206 connected = false; 207 } 208 else if (event instanceof ClassPrepareEvent) { 209 // watch field on loaded class 210 System.out.println("ClassPrepareEvent"); 211 ClassPrepareEvent classPrepEvent = (ClassPrepareEvent) event; 212 ReferenceType refType = classPrepEvent.referenceType(); 213 addBreakpoint(vm, refType); 214 } else if (event instanceof BreakpointEvent) { 215 recursionCount = getLockRecursions(vm); 216 System.out.println("resume..."); 217 } 218 } 219 eventSet.resume(); 220 } 221 // Shutdown begins when event thread terminates 222 try { 223 errThread.join(); // Make sure output is forwarded 224 outThread.join(); 225 } catch (InterruptedException e) { 226 // we don't interrupt 227 e.printStackTrace(); 228 } 229 if (recursionCount != 3) { 230 throw new AssertionError("recursions: expected 3, but was " + recursionCount); 231 } 232 } 233 234 public static int getLockRecursions(VirtualMachine vm) { 235 List <ThreadReference> threads = vm.allThreads(); 236 for (ThreadReference thread : threads) { 237 if (thread.name().equals("main")) { 238 239 System.out.println("Found main thread."); 240 try{ 241 StackFrame frame = thread.frame(3); 242 return frame.thisObject().entryCount(); 243 } catch (Exception e) { 244 e.printStackTrace(); 245 } 246 } 247 System.out.println("Main thread not found!"); 248 } 249 return -1; 250 } 251 } 252 253 class StreamRedirectThread extends Thread { 254 255 private final BufferedReader in; 256 257 private static final int BUFFER_SIZE = 2048; 258 259 /** 260 * Set up for copy. 261 * @param name Name of the thread 262 * @param in Stream to copy from 263 */ 264 StreamRedirectThread(String name, InputStream in) { 265 super(name); 266 this.in = new BufferedReader(new InputStreamReader(in)); 267 } 268 269 /** 270 * Copy. 271 */ 272 public void run() { 273 try { 274 String line; 275 while ((line = in.readLine ()) != null) { 276 System.out.println("testvm: " + line); 277 } 278 System.out.flush(); 279 } catch(IOException exc) { 280 System.err.println("Child I/O Transfer - " + exc); 281 exc.printStackTrace(); 282 } 283 } 284 }