GetObjectLockCount.java revision 10049:73443d24e529
16627Sjkh/*
26627Sjkh * Copyright (c) 2014 SAP SE. All rights reserved.
36627Sjkh * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
46627Sjkh *
56627Sjkh * This code is free software; you can redistribute it and/or modify it
66627Sjkh * under the terms of the GNU General Public License version 2 only, as
76627Sjkh * published by the Free Software Foundation.
86627Sjkh *
96627Sjkh * This code is distributed in the hope that it will be useful, but WITHOUT
106627Sjkh * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
116627Sjkh * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
126627Sjkh * version 2 for more details (a copy is included in the LICENSE file that
136627Sjkh * accompanied this code).
1489612Smpp *
156627Sjkh * You should have received a copy of the GNU General Public License version
166627Sjkh * 2 along with this work; if not, write to the Free Software Foundation,
176627Sjkh * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
186627Sjkh *
196627Sjkh * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
206627Sjkh * or visit www.oracle.com if you need additional information or have any
216627Sjkh * questions.
226627Sjkh */
236627Sjkh
246627Sjkhimport java.io.BufferedReader;
256627Sjkhimport java.io.IOException;
266627Sjkhimport java.io.InputStream;
2750476Speterimport java.io.InputStreamReader;
286627Sjkhimport java.util.Iterator;
29177292Sbruefferimport java.util.List;
30203692Sgavinimport java.util.Map;
3179538Sru
326627Sjkhimport com.sun.jdi.AbsentInformationException;
336627Sjkhimport com.sun.jdi.Bootstrap;
346627Sjkhimport com.sun.jdi.LocalVariable;
356627Sjkhimport com.sun.jdi.Location;
36177292Sbruefferimport com.sun.jdi.ObjectReference;
3784877Syokotaimport com.sun.jdi.ReferenceType;
3884877Syokotaimport com.sun.jdi.StackFrame;
3984877Syokotaimport com.sun.jdi.ThreadReference;
4084877Syokotaimport com.sun.jdi.Value;
4184877Syokotaimport com.sun.jdi.VirtualMachine;
426627Sjkhimport com.sun.jdi.connect.Connector;
436627Sjkhimport com.sun.jdi.connect.Connector.Argument;
4468962Sruimport com.sun.jdi.connect.IllegalConnectorArgumentsException;
456627Sjkhimport com.sun.jdi.connect.LaunchingConnector;
46131530Sruimport com.sun.jdi.connect.VMStartException;
47131530Sruimport com.sun.jdi.event.BreakpointEvent;
486627Sjkhimport com.sun.jdi.event.ClassPrepareEvent;
496627Sjkhimport com.sun.jdi.event.Event;
5015128Smppimport com.sun.jdi.event.EventQueue;
5115128Smppimport com.sun.jdi.event.EventSet;
5281622Sruimport com.sun.jdi.event.VMDeathEvent;
5381622Sruimport com.sun.jdi.event.VMDisconnectEvent;
5481622Sruimport com.sun.jdi.event.VMStartEvent;
556627Sjkhimport com.sun.jdi.request.BreakpointRequest;
56107788Sruimport com.sun.jdi.request.ClassPrepareRequest;
5715128Smppimport com.sun.jdi.request.EventRequestManager;
586627Sjkh
5970466Sru
606627Sjkh/*
61143673Sbrueffer * @test GetObjectLockCount.java
62140561Sru * @bug 8036666
63140561Sru * @key regression
64140561Sru * @summary verify jvm returns correct lock recursion count
65140561Sru * @run compile -g RecursiveObjectLock.java
66140561Sru * @run main/othervm GetObjectLockCount
676627Sjkh * @author axel.siebenborn@sap.com
6869027Sru */
6934504Scharnier
7034504Scharnierpublic class GetObjectLockCount {
7134504Scharnier
7234504Scharnier    public static final String CLASS_NAME  = "RecursiveObjectLock";
7334504Scharnier    public static final String METHOD_NAME = "breakpoint1";
7434504Scharnier    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
253class 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}
285