blob: e7e4cd0815064269457dd6ff82b34b06281d9e55 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2006-2007 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
20 * CA 95054 USA or visit www.sun.com if you need additional information or
21 * have any questions.
22 */
23
24/**
25 * @test
26 * @bug 6293795
27 * @summary Backend hangs when invokeMethod is called from a JDI eventHandler
28 *
29 * @author jjh
30 *
31 * @run build TestScaffold VMConnection TargetListener TargetAdapter
32 * @run compile -g InvokeHangTest.java
33 * @run main InvokeHangTest
34 */
35import com.sun.jdi.*;
36import com.sun.jdi.event.*;
37import com.sun.jdi.request.*;
38
39import java.util.*;
40
41/*
42 * This debuggee basically runs two threads each of
43 * which loop, hitting a bkpt in each iteration.
44 *
45 */
46class InvokeHangTarg extends Thread {
47 static boolean one = false;
48 static String name1 = "Thread 1";
49 static String name2 = "Thread 2";
50 static int count = 100;
51
52 public static void main(String[] args) {
53 System.out.println("Howdy!");
54 InvokeHangTarg t1 = new InvokeHangTarg(name1);
55 InvokeHangTarg t2 = new InvokeHangTarg(name2);
56
57 t1.start();
58 t2.start();
59 }
60
61 // This is called from the debugger via invokeMethod
62 public double invokeee() {
63 System.out.println("Debuggee: invokeee in thread "+Thread.currentThread().toString());
64 yield();
65 return longMethod(2);
66 }
67 public double longMethod(int n) {
68 double a = 0;
69 double s = 0;
70 for (int i = 0; i < n; i++) {
71 a += i;
72 for (int j = -1000*i; j < 1000*i; j++) {
73 a = a*(1 + i/(j + 0.5));
74 s += Math.sin(a);
75 }
76 }
77 System.out.println("Debuggee: invokeee finished");
78 return s;
79 }
80
81 public InvokeHangTarg(String name) {
82 super(name);
83 }
84
85 public void run() {
86 if (getName().equals(name1)) {
87 run1();
88 } else {
89 run2();
90 }
91 }
92
93 public void bkpt1(int i) {
94 System.out.println("Debuggee: " + Thread.currentThread() +" is running:" + i);
95 try {
96 Thread.currentThread().sleep(2);
97 } catch (InterruptedException iex) {}
98 //yield();
99 }
100
101 public void run1() {
102 int i = 0;
103 while (i < count) {
104 i++;
105 bkpt1(i);
106 }
107 }
108
109 public void bkpt2(int i) {
110 System.out.println("Debuggee: " + Thread.currentThread() +" is running:" + i);
111 try {
112 Thread.currentThread().sleep(2);
113 } catch (InterruptedException iex) {}
114 //yield();
115 }
116
117 public void run2() {
118 int i = 0;
119 while (i < count) {
120 i++;
121 bkpt2(i);
122 }
123 }
124}
125
126/********** test program **********/
127
128public class InvokeHangTest extends TestScaffold {
129 ReferenceType targetClass;
130 ThreadReference mainThread;
131 BreakpointRequest request1;
132 BreakpointRequest request2;
133 static volatile int bkpts = 0;
134 Thread timerThread;
135 static int waitTime = 20000;
136
137 InvokeHangTest (String args[]) {
138 super(args);
139 }
140
141 public static void main(String[] args) throws Exception {
142 new InvokeHangTest(args).startTests();
143 }
144
145 void doInvoke(ThreadReference thread, ObjectReference ref, String methodName) {
146 List methods = ref.referenceType().methodsByName(methodName);
147 Method method = (Method) methods.get(0);
148 try {
149 System.err.println(" Debugger: Invoking in thread" + thread);
150 ref.invokeMethod(thread, method, new ArrayList(), ref.INVOKE_NONVIRTUAL);
151 System.err.println(" Debugger: Invoke done");
152 } catch (Exception ex) {
153 ex.printStackTrace();
154 failure("failure: Exception");
155 }
156 }
157
158 // BreakpointEvent handler
159 public void breakpointReached(BreakpointEvent event) {
160 if (bkpts == 0) {
161 /*
162 * This thread will watch for n secs to go by with no
163 * calls to this method.
164 */
165 timerThread.start();
166 }
167
168 synchronized("abc") {
169 /*
170 * Note that this will most likely never get to
171 * the number of times the two bkpt lines in the debuggee
172 * are hit because bkpts are lost while they are disabled.
173 */
174 bkpts++;
175 }
176
177 /*
178 * The bug occurs when the requests are disabled
179 * and then an invoke is done in the event handler. In some cases
180 * the other thread has hit a bkpt and the back-end is waiting
181 * to send it. When the back-end resumes the debuggee to do the
182 * invokeMethod, this 2nd bkpt is released, the debuggee is suspended, including
183 * the thread on which the invoke was done (because it is a SUSPEND_ALL bkpt),
184 * the bkpt is sent to the front-end, but the client event handler is sitting
185 * here waiting for the invoke to finish, so it doesn't get the 2nd bkpt and
186 * do the resume for it. Thus, the debuggee is suspended waiting for a resume
187 * that never comes.
188 */
189 request1.disable();
190 request2.disable();
191
192 ThreadReference thread = event.thread();
193 try {
194 StackFrame sf = thread.frame(0);
195 System.err.println(" Debugger: Breakpoint hit at "+sf.location());
196 doInvoke(thread, sf.thisObject(), "invokeee");
197 } catch (IncompatibleThreadStateException itsex) {
198 itsex.printStackTrace();
199 failure("failure: Exception");
200 }
201 request1.enable();
202 request2.enable();
203
204 }
205
206 /********** test core **********/
207
208 protected void runTests() throws Exception {
209
210 /*
211 * Get to the top of main()
212 * to determine targetClass and mainThread
213 */
214 BreakpointEvent bpe = startToMain("InvokeHangTarg");
215 targetClass = bpe.location().declaringType();
216 mainThread = bpe.thread();
217 EventRequestManager erm = vm().eventRequestManager();
218 final Thread mainThread = Thread.currentThread();
219
220 /*
221 * Set event requests
222 */
223 Location loc1 = findMethod(targetClass, "bkpt1", "(I)V").location();
224 Location loc2 = findMethod(targetClass, "bkpt2", "(I)V").location();
225 request1 = erm.createBreakpointRequest(loc1);
226 request2 = erm.createBreakpointRequest(loc2);
227 request1.enable();
228 request2.enable();
229
230 /*
231 * This thread will be started when we get the first bkpt.
232 * (Which we always expect to get).
233 * It awakens every n seconds and checks to see if we
234 * got any breakpoint events while it was asleep. If not, then
235 * we assume the debuggee is hung and fail the test.
236 */
237 timerThread = new Thread("test timer") {
238 public void run() {
239 int myBkpts = bkpts;
240 while (true) {
241 try {
242 Thread.sleep(waitTime);
243 System.out.println("bkpts = " + bkpts);
244 if (myBkpts == bkpts) {
245 // no bkpt for 'waitTime' msecs
246 failure("failure: Debuggee appears to be hung");
247 vmDisconnected = true;
248 // This awakens the main thread which is
249 // waiting for a VMDisconnect.
250 mainThread.interrupt();
251 break;
252 }
253 myBkpts = bkpts;
254 } catch (InterruptedException ee) {
255 // If the test completes, this occurs.
256 println("timer Interrupted");
257 break;
258 }
259 }
260 }
261 };
262
263 /*
264 * resume the target, listening for events
265 */
266 listenUntilVMDisconnect();
267 timerThread.interrupt();
268 /*
269 * deal with results of test
270 * if anything has called failure("foo") testFailed will be true
271 */
272 if (!testFailed) {
273 println("InvokeHangTest: passed; bkpts = " + bkpts);
274 } else {
275 throw new Exception("InvokeHangTest: failed; bkpts = " + bkpts);
276 }
277 }
278}