blob: c1cb6f1a36378c43a906f0eab666973ea258b0f5 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2005 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 6296125
27 * @summary JDI: Disabling an EventRequest can cause a multi-threaded debuggee to hang
28 *
29 * @author jjh
30 *
31 * @run build TestScaffold VMConnection TargetListener TargetAdapter
32 * @run compile -g TwoThreadsTest.java
33 * @run main TwoThreadsTest
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 TwoThreadsTarg 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 TwoThreadsTarg t1 = new TwoThreadsTarg(name1);
55 TwoThreadsTarg t2 = new TwoThreadsTarg(name2);
56
57 t1.start();
58 t2.start();
59 }
60
61 public TwoThreadsTarg(String name) {
62 super(name);
63 }
64
65 public void run() {
66 if (getName().equals(name1)) {
67 run1();
68 } else {
69 run2();
70 }
71 }
72
73 public void bkpt1(int i) {
74 yield();
75 }
76
77 public void run1() {
78 int i = 0;
79 while (i < count) {
80 i++;
81 bkpt1(i);
82 }
83 }
84
85 public void bkpt2(int i) {
86 yield();
87 }
88
89 public void run2() {
90 int i = 0;
91 while (i < count) {
92 i++;
93 bkpt2(i);
94 }
95 }
96}
97
98/********** test program **********/
99
100public class TwoThreadsTest extends TestScaffold {
101 ReferenceType targetClass;
102 ThreadReference mainThread;
103 BreakpointRequest request1;
104 BreakpointRequest request2;
105 static volatile int bkpts = 0;
106 Thread timerThread;
107 static int waitTime = 20000;
108
109 TwoThreadsTest (String args[]) {
110 super(args);
111 }
112
113 public static void main(String[] args) throws Exception {
114 new TwoThreadsTest(args).startTests();
115 }
116
117 /* BreakpointEvent handler */
118
119 public void breakpointReached(BreakpointEvent event) {
120 if (bkpts == 0) {
121 /*
122 * This thread will watch for n secs to go by with no
123 * calls to this method.
124 */
125 timerThread.start();
126 }
127
128 synchronized("abc") {
129 /*
130 * Note that this will most likely never get to
131 * the number of times the two bkpt lines in the debuggee
132 * are hit because bkpts are lost while they are disabled.
133 */
134 bkpts++;
135 }
136
137 /*
138 * The bug occurs when the requests are disabled
139 * and then re-enabled during the event handler.
140 */
141 request1.disable();
142 request2.disable();
143
144 /*
145 * This code between the disables and enables
146 * is just filler that leaves the requests disabled
147 * for awhile. I suppose a sleep could be used instead
148 */
149 Method mmm = event.location().method();
150 List lvlist;
151 try {
152 lvlist = mmm.variablesByName("i");
153 } catch (AbsentInformationException ee) {
154 failure("FAILED: can't get local var i");
155 return;
156 }
157 LocalVariable ivar = (LocalVariable)lvlist.get(0);
158
159 ThreadReference thr = event.thread();
160 StackFrame sf;
161 try {
162 sf = thr.frame(0);
163 } catch (IncompatibleThreadStateException ee) {
164 failure("FAILED: bad thread state");
165 return;
166 }
167 Value ival = sf.getValue(ivar);
168 println("Got bkpt at: " + event.location() + ", i = " + ival);
169 request1.enable();
170 request2.enable();
171
172 }
173
174 /********** test core **********/
175
176 protected void runTests() throws Exception {
177
178 /*
179 * Get to the top of main()
180 * to determine targetClass and mainThread
181 */
182 BreakpointEvent bpe = startToMain("TwoThreadsTarg");
183 targetClass = bpe.location().declaringType();
184 mainThread = bpe.thread();
185 EventRequestManager erm = vm().eventRequestManager();
186 final Thread mainThread = Thread.currentThread();
187
188 /*
189 * Set event requests
190 */
191 Location loc1 = findMethod(targetClass, "bkpt1", "(I)V").location();
192 Location loc2 = findMethod(targetClass, "bkpt2", "(I)V").location();
193 request1 = erm.createBreakpointRequest(loc1);
194 request2 = erm.createBreakpointRequest(loc2);
195 request1.enable();
196 request2.enable();
197
198 /*
199 * This thread will be started when we get the first bkpt.
200 * (Which we always expect to get).
201 * It awakens every n seconds and checks to see if we
202 * got any breakpoint events while it was asleep.
203 */
204 timerThread = new Thread("test timer") {
205 public void run() {
206 int myBkpts = bkpts;
207 while (true) {
208 try {
209 Thread.sleep(waitTime);
210 System.out.println("bkpts = " + bkpts);
211 if (myBkpts == bkpts) {
212 // no bkpt for 'waitTime' secs
213 failure("failure: Debuggee appears to be hung");
214 vmDisconnected = true;
215 // This awakens the main thread which is
216 // waiting for a VMDisconnect.
217 mainThread.interrupt();
218 break;
219 }
220 myBkpts = bkpts;
221 } catch (InterruptedException ee) {
222 // If the test completes, this occurs.
223 println("timer Interrupted");
224 break;
225 }
226 }
227 }
228 };
229
230 /*
231 * resume the target, listening for events
232 */
233 listenUntilVMDisconnect();
234 timerThread.interrupt();
235 /*
236 * deal with results of test
237 * if anything has called failure("foo") testFailed will be true
238 */
239 if (!testFailed) {
240 println("TwoThreadsTest: passed; bkpts = " + bkpts);
241 } else {
242 throw new Exception("TwoThreadsTest: failed; bkpts = " + bkpts);
243 }
244 }
245}