1/*
2 * Copyright (c) 2008, 2015, 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 */
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 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;
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
60    public SimulResumerTarg(String name) {
61        super(name);
62    }
63
64    public void run() {
65        if (getName().equals(name1)) {
66            run1();
67        } else {
68            run2();
69        }
70    }
71
72    public void bkpt1(int i) {
73        synchronized(name1) {
74            yield();
75        }
76    }
77
78    public void run1() {
79        int i = 0;
80        while (i < count) {
81            i++;
82            bkpt1(i);
83        }
84    }
85
86    public void bkpt2(int i) {
87        synchronized(name2) {
88            yield();
89        }
90    }
91
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
103public 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
115    SimulResumerTest (String args[]) {
116        super(args);
117    }
118
119    public static void main(String[] args)      throws Exception {
120        new SimulResumerTest(args).startTests();
121    }
122
123    /* BreakpointEvent handler */
124
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
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
214            } catch (VMDisconnectedException ee) {
215                // This is how we stop.  The debuggee runs to completion
216                // and we get this exception.
217                throw ee;
218            } catch (Exception ee) {
219                failure("failure: Got exception from " + kind + ": " + ee );
220            }
221        }
222    }
223
224    protected void runTests() throws Exception {
225        /*
226         * Get to the top of main()
227         * to determine targetClass and mainThread
228         */
229        BreakpointEvent bpe = startToMain("SimulResumerTarg");
230        targetClass = bpe.location().declaringType();
231        mainThread = bpe.thread();
232        EventRequestManager erm = vm().eventRequestManager();
233        final Thread mainThread = Thread.currentThread();
234
235        /*
236         * Set event requests
237         */
238        Location loc1 = findMethod(targetClass, "bkpt1", "(I)V").location();
239        Location loc2 = findMethod(targetClass, "bkpt2", "(I)V").location();
240        request1 = erm.createBreakpointRequest(loc1);
241        request2 = erm.createBreakpointRequest(loc2);
242        request1.enable();
243        request2.enable();
244
245        /*
246         * This thread will be started when we get the first bkpt.
247         */
248        resumerThread = new Thread("test resumer") {
249                public void run() {
250                    while (true) {
251                        iters++;
252                        System.out.println("bkpts = " + bkpts + ", iters = " + iters);
253                        try {
254                            Thread.sleep(waitTime);
255                            check(debuggeeThread1);
256                            check(debuggeeThread2);
257                        } catch (InterruptedException ee) {
258                            // If the test completes, this occurs.
259                            println("resumer Interrupted");
260                            break;
261                        } catch (VMDisconnectedException ee) {
262                            println("VMDisconnectedException");
263                            break;
264                        }
265                    }
266                }
267            };
268
269        /*
270         * resume the target, listening for events
271         */
272        listenUntilVMDisconnect();
273        resumerThread.interrupt();
274        /*
275         * deal with results of test
276         * if anything has called failure("foo") testFailed will be true
277         */
278        if (!testFailed) {
279            println("SimulResumerTest: passed; bkpts = " + bkpts + ", iters = " + iters);
280        } else {
281            throw new Exception("SimulResumerTest: failed; bkpts = " + bkpts + ", iters = " + iters);
282        }
283    }
284}
285