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