1 /*
2  * Copyright (c) 2008, 2019, Oracle and/or its affiliates. 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 /**
25  * @test
26  * @bug 6751643
27  * @key intermittent
28  * @summary ThreadReference.ownedMonitors() can return null
29  * @author jjh
30  *
31  * @run build TestScaffold VMConnection TargetListener TargetAdapter
32  * @run compile -g SimulResumerTest.java
33  * @run driver SimulResumerTest
34  */
35 import com.sun.jdi.*;
36 import com.sun.jdi.event.*;
37 import com.sun.jdi.request.*;
38 
39 import java.util.*;
40 
41 /*
42  * This debuggee basically runs two threads each of
43  * which loop, hitting a bkpt in each iteration.
44  *
45  */
46 class SimulResumerTarg extends Thread {
47     static boolean one = false;
48     static String name1 = "Thread 1";
49     static String name2 = "Thread 2";
50     static int count = 10000;
main(String[] args)51     public static void main(String[] args) {
52         System.out.println("Howdy!");
53         SimulResumerTarg t1 = new SimulResumerTarg(name1);
54         SimulResumerTarg t2 = new SimulResumerTarg(name2);
55 
56         t1.start();
57         t2.start();
58     }
59 
SimulResumerTarg(String name)60     public SimulResumerTarg(String name) {
61         super(name);
62     }
63 
run()64     public void run() {
65         if (getName().equals(name1)) {
66             run1();
67         } else {
68             run2();
69         }
70     }
71 
bkpt1(int i)72     public void bkpt1(int i) {
73         synchronized(name1) {
74             Thread.yield();
75         }
76     }
77 
run1()78     public void run1() {
79         int i = 0;
80         while (i < count) {
81             i++;
82             bkpt1(i);
83         }
84     }
85 
bkpt2(int i)86     public void bkpt2(int i) {
87         synchronized(name2) {
88             Thread.yield();
89         }
90     }
91 
run2()92     public void run2() {
93         int i = 0;
94         while (i < count) {
95             i++;
96             bkpt2(i);
97         }
98     }
99 }
100 
101 /********** test program **********/
102 
103 public class SimulResumerTest extends TestScaffold {
104     ReferenceType targetClass;
105     ThreadReference mainThread;
106     BreakpointRequest request1;
107     BreakpointRequest request2;
108     static volatile int bkpts = 0;
109     static int iters = 0;
110     Thread resumerThread;
111     static int waitTime = 100;
112     ThreadReference debuggeeThread1 = null;
113     ThreadReference debuggeeThread2 = null;
114 
SimulResumerTest(String args[])115     SimulResumerTest (String args[]) {
116         super(args);
117     }
118 
main(String[] args)119     public static void main(String[] args)      throws Exception {
120         new SimulResumerTest(args).startTests();
121     }
122 
123     /* BreakpointEvent handler */
124 
breakpointReached(BreakpointEvent event)125     public void breakpointReached(BreakpointEvent event) {
126         // save ThreadRefs for the two debuggee threads
127         ThreadReference thr = event.thread();
128         if (bkpts == 0) {
129             resumerThread.start();
130             debuggeeThread1 = thr;
131             System.out.println("thr1 = " + debuggeeThread1);
132         }
133 
134         if (debuggeeThread2 == null && thr != debuggeeThread1) {
135             debuggeeThread2 = thr;
136             System.out.println("thr2 = " + debuggeeThread2);
137         }
138 
139         synchronized("abc") {
140             bkpts++;
141         }
142         /**
143         if (bkpts >= SimulResumerTarg.count * 2) {
144             resumerThread.interrupt();
145         }
146         *****/
147 
148     }
149 
150     /********** test core **********/
151 
check(ThreadReference thr)152     void check(ThreadReference thr) {
153         // This calls each ThreadReference method that could fail due to the bug
154         // that occurs if a resume is done while a call to the method is in process.
155         String kind = "";
156         if (thr != null) {
157             try {
158                 kind = "ownedMonitors()";
159                 System.out.println("kind = " + kind);
160                 if (thr.ownedMonitors() == null) {
161                     failure("failure: ownedMonitors = null");
162                 }
163 
164                 kind = "ownedMonitorsAndFrames()";
165                 System.out.println("kind = " + kind);
166                 if (thr.ownedMonitorsAndFrames() == null) {
167                     failure("failure: ownedMonitorsAndFrames = null");
168                 }
169 
170                 kind = "currentContendedMonitor()";
171                 System.out.println("kind = " + kind);
172                 thr.currentContendedMonitor();
173                 // no failure return value here; could cause an NPE
174 
175                 kind = "frames()";
176                 System.out.println("kind = " + kind);
177                 List<StackFrame> frames = thr.frames();
178                 // no failure return value here; could cause an NPE
179 
180                 kind = "frames(0, size - 1)";
181                 System.out.println("kind = " + kind);
182                 int nframes = frames.size();
183                 while (nframes > 0) {
184                     try {
185                         thr.frames(0, nframes - 1);
186                         break;
187                     } catch (IndexOutOfBoundsException iobe) {
188                         // 6815126. let's try to get less frames
189                         iobe.printStackTrace();
190                         nframes--;
191                     }
192                 }
193 
194                 kind = "frameCount()";
195                 System.out.println("kind = " + kind);
196                 if (thr.frameCount() == -1) {
197                     failure("failure: frameCount = -1");
198                 }
199 
200                 kind = "name()";
201                 System.out.println("kind = " + kind);
202                 if (thr.name() == null) {
203                     failure("failure: name = null");
204                 }
205 
206                 kind = "status()";
207                 System.out.println("kind = " + kind);
208                 if (thr.status() < 0) {
209                     failure("failure: status < 0");
210                 }
211 
212             } catch (IncompatibleThreadStateException ee) {
213                 // ignore checks if thread was not suspended
214             } catch (ObjectCollectedException ee) {
215                 // ignore ownedMonitors failure
216             } catch (VMDisconnectedException ee) {
217                 // This is how we stop.  The debuggee runs to completion
218                 // and we get this exception.
219                 throw ee;
220             } catch (Exception ee) {
221                 failure("failure: Got exception from " + kind + ": " + ee );
222             }
223         }
224     }
225 
runTests()226     protected void runTests() throws Exception {
227         /*
228          * Get to the top of main()
229          * to determine targetClass and mainThread
230          */
231         BreakpointEvent bpe = startToMain("SimulResumerTarg");
232         targetClass = bpe.location().declaringType();
233         mainThread = bpe.thread();
234         EventRequestManager erm = vm().eventRequestManager();
235         final Thread mainThread = Thread.currentThread();
236 
237         /*
238          * Set event requests
239          */
240         Location loc1 = findMethod(targetClass, "bkpt1", "(I)V").location();
241         Location loc2 = findMethod(targetClass, "bkpt2", "(I)V").location();
242         request1 = erm.createBreakpointRequest(loc1);
243         request2 = erm.createBreakpointRequest(loc2);
244         request1.enable();
245         request2.enable();
246 
247         /*
248          * This thread will be started when we get the first bkpt.
249          */
250         resumerThread = new Thread("test resumer") {
251                 public void run() {
252                     while (true) {
253                         iters++;
254                         // System.out.println("bkpts = " + bkpts + ", iters = " + iters);
255                         try {
256                             Thread.sleep(waitTime);
257                             check(debuggeeThread1);
258                             check(debuggeeThread2);
259                         } catch (InterruptedException ee) {
260                             // If the test completes, this occurs.
261                             println("resumer Interrupted");
262                             break;
263                         } catch (VMDisconnectedException ee) {
264                             println("VMDisconnectedException");
265                             break;
266                         }
267                     }
268                 }
269             };
270 
271         /*
272          * resume the target, listening for events
273          */
274         listenUntilVMDisconnect();
275         resumerThread.interrupt();
276         /*
277          * deal with results of test
278          * if anything has called failure("foo") testFailed will be true
279          */
280         if (!testFailed) {
281             println("SimulResumerTest: passed; bkpts = " + bkpts + ", iters = " + iters);
282         } else {
283             throw new Exception("SimulResumerTest: failed; bkpts = " + bkpts + ", iters = " + iters);
284         }
285     }
286 }
287