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