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 6700889
27 * @summary  Thread resume invalidates all stack frames, even from other threads
28 * @author jjh
29 *
30 * @run build TestScaffold VMConnection TargetListener TargetAdapter
31 * @run compile -g ResumeOneThreadTest.java
32 * @run driver ResumeOneThreadTest
33 */
34import com.sun.jdi.*;
35import com.sun.jdi.event.*;
36import com.sun.jdi.request.*;
37
38import java.util.*;
39
40class ResumeOneThreadTarg extends Thread {
41    static String name1 = "Thread 1";
42    static String name2 = "Thread 2";
43
44    public ResumeOneThreadTarg(String name) {
45        super(name);
46    }
47
48    public static void main(String[] args) {
49        System.out.println("    Debuggee: Howdy!");
50        ResumeOneThreadTarg t1 = new ResumeOneThreadTarg(name1);
51        ResumeOneThreadTarg t2 = new ResumeOneThreadTarg(name2);
52
53        t1.start();
54        t2.start();
55    }
56
57    // This just starts two threads. Each runs to a bkpt.
58    public void run() {
59        if (getName().equals(name1)) {
60            run1();
61        } else {
62            run2();
63        }
64    }
65
66    public void bkpt1(String p1) {
67        System.out.println("    Debuggee: bkpt 1");
68    }
69
70    public void run1() {
71        bkpt1("Hello Alviso!");
72    }
73
74
75
76    public void bkpt2() {
77        System.out.println("    Debuggee: bkpt 2");
78    }
79
80    public void run2() {
81        bkpt2();
82    }
83}
84
85/********** test program **********/
86
87public class ResumeOneThreadTest extends TestScaffold {
88    ReferenceType targetClass;
89    ThreadReference mainThread;
90
91    BreakpointRequest request1;
92    BreakpointRequest request2;
93
94    ThreadReference thread1 = null;
95    ThreadReference thread2 = null;;
96    boolean theVMisDead = false;
97
98    ResumeOneThreadTest (String args[]) {
99        super(args);
100    }
101
102    public static void main(String[] args)      throws Exception {
103        new ResumeOneThreadTest(args).startTests();
104    }
105
106
107    synchronized public void breakpointReached(BreakpointEvent event) {
108        println("-- Got bkpt at: " + event.location());
109        ThreadReference eventThread = event.thread();
110
111        if (eventThread.name().equals(ResumeOneThreadTarg.name1)) {
112            thread1 = eventThread;
113        }
114
115        if (eventThread.name().equals(ResumeOneThreadTarg.name2)) {
116            thread2 = eventThread;
117        }
118    }
119
120    public void vmDied(VMDeathEvent event) {
121        theVMisDead = true;
122    }
123
124    synchronized public void eventSetComplete(EventSet set) {
125        if (theVMisDead) {
126            return;
127        }
128        if (thread1 == null || thread2 == null) {
129            // Don't do a set.resume(), just let the other thread
130            // keep running until it hits its bkpt.
131            return;
132        }
133
134        // Both threads are stopped at their bkpts.  Get a StackFrame from
135        // Thread 1 then resume Thread 2 and verify that the saved StackFrame is
136        // still valid.
137
138        // suspend everything.
139        println("-- All threads suspended");
140        vm().suspend();
141
142        StackFrame t1sf0 = null;
143        try {
144            t1sf0 = thread1.frame(0);
145        } catch (IncompatibleThreadStateException ee) {
146            failure("FAILED: Exception: " + ee);
147        }
148
149        println("-- t1sf0 args: " + t1sf0.getArgumentValues());
150
151        // Ok, we have a StackFrame for thread 1.  Resume just thread 2
152        // Note that thread 2 has been suspended twice - by the SUSPEND_ALL
153        // bkpt, and by the above vm().suspend(), so we have to resume
154        // it twice.
155        request2.disable();
156
157        thread2.resume();
158        thread2.resume();
159        println("-- Did Resume on thread 2");
160
161        // Can we get frames for thread1?
162        try {
163            StackFrame t1sf0_1 = thread1.frame(0);
164            if (!t1sf0.equals(t1sf0_1)) {
165                failure("FAILED: Got a different frame 0 for thread 1 after resuming thread 2");
166            }
167        } catch (IncompatibleThreadStateException ee) {
168            failure("FAILED: Could not get frames for thread 1: Exception: " + ee);
169        } catch (Exception ee) {
170            failure("FAILED: Could not get frames for thread 1: Exception: " + ee);
171        }
172
173
174        try {
175            println("-- t1sf0 args: " + t1sf0.getArgumentValues());
176        } catch (InvalidStackFrameException ee) {
177            // This is the failure.
178            failure("FAILED Got InvalidStackFrameException");
179            vm().dispose();
180            throw(ee);
181        }
182
183        // Let the debuggee finish
184        request1.disable();
185        thread1.resume();
186        vm().resume();
187        println("--------------");
188    }
189
190    /********** test core **********/
191
192    protected void runTests() throws Exception {
193
194        /*
195         * Get to the top of main()
196         * to determine targetClass and mainThread
197         */
198        BreakpointEvent bpe = startToMain("ResumeOneThreadTarg");
199        targetClass = bpe.location().declaringType();
200        mainThread = bpe.thread();
201        EventRequestManager erm = vm().eventRequestManager();
202        final Thread mainThread = Thread.currentThread();
203
204        /*
205         * Set event requests
206         */
207
208        Location loc1 = findMethod(targetClass, "bkpt1", "(Ljava/lang/String;)V").location();
209        request1 = erm.createBreakpointRequest(loc1);
210        request1.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
211        request1.enable();
212
213        Location loc2 = findMethod(targetClass, "bkpt2", "()V").location();
214        request2 = erm.createBreakpointRequest(loc2);
215        request2.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
216        request2.enable();
217
218        /*
219         * resume the target, listening for events
220         */
221        listenUntilVMDisconnect();
222        /*
223         * deal with results of test
224         * if anything has called failure("foo") testFailed will be true
225         */
226        if (!testFailed) {
227            println("ResumeOneThreadTest: passed");
228        } else {
229            throw new Exception("ResumeOneThreadTest: failed");
230        }
231    }
232}
233