/* * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ /** * @test * @bug 4359247 * @summary Breakpoints on multiple threads have problems. * @author tbell, jjh * * @build TestScaffold VMConnection TargetListener TargetAdapter * @run compile -g MultiBreakpointsTest.java * @run driver MultiBreakpointsTest */ /* * This test runs a debuggee with n threads each of which just loops * doing some printlns and calling a method. The debugger sets * bkpts on these methods and verifies that they are all hit. * The default number of threads is 4. To change it to say 10, * pass this to the testcase on the cmd line: * -Dnthreads=10 * The current max allowed value of nthreads is 30. * You can also do this, for example, * -Dnhits=30 * to change the number of times the bkpts are to be hit from * the default of 100 to 30. */ import com.sun.jdi.*; import com.sun.jdi.event.*; import com.sun.jdi.request.*; import java.util.*; /********** target program **********/ import java.io.*; import java.text.*; class MultiBreakpointsTarg { MultiBreakpointsTarg(int numThreads, int numHits) { for (int ii = 0; ii < numThreads; ii++) { console(ii, numHits); } } public static void main(String args[]) { int nthreads; int nhits; String nStr = System.getProperty("nthreads"); if (nStr == null) { throw new RuntimeException("nthreads = null in debuggee"); } nthreads = Integer.parseInt(nStr); nStr = System.getProperty("nhits"); if (nStr == null) { throw new RuntimeException("nhits = null in debuggee"); } nhits = Integer.parseInt(nStr); System.out.println("Debuggee: nthreads = " + nthreads + ", nhits = " + nhits); MultiBreakpointsTarg ptr = new MultiBreakpointsTarg(nthreads, nhits); // for (int i = 0; i < nthreads; i++) { // ptr.console(i); // } } // The brute force approach for simplicity - don't use reflection // nor set thread specific bkpts. Use of those features would // make for interesting tests too, and maybe would prove that // we don't really have to bother doing it this dumb way. void bkpt0() {} void bkpt1() {} void bkpt2() {} void bkpt3() {} void bkpt4() {} void bkpt5() {} void bkpt6() {} void bkpt7() {} void bkpt8() {} void bkpt9() {} void bkpt10() {} void bkpt11() {} void bkpt12() {} void bkpt13() {} void bkpt14() {} void bkpt15() {} void bkpt16() {} void bkpt17() {} void bkpt18() {} void bkpt19() {} void bkpt20() {} void bkpt21() {} void bkpt22() {} void bkpt23() {} void bkpt24() {} void bkpt25() {} void bkpt26() {} void bkpt27() {} void bkpt28() {} void bkpt29() {} void console(final int num, final int nhits) { final InputStreamReader isr = new InputStreamReader(System.in); final BufferedReader br = new BufferedReader(isr); // Create the threads // //final String threadName = "DebuggeeThread: " + num; final String threadName = "" + num; Thread thrd = new Thread( threadName ) { public void run() { synchronized( isr ) { boolean done = false; try { // For each thread, run until numHits bkpts have been hit for( int i = 0; i < nhits; i++ ) { // This is a tendril from the original jdb test. // It could probably be deleted. System.out.println("Thread " + threadName + " Enter a string: "); String s = "test" + num; switch (num) { case 0: bkpt0(); break; case 1: bkpt1(); break; case 2: bkpt2(); break; case 3: bkpt3(); break; case 4: bkpt4(); break; case 5: bkpt5(); break; case 6: bkpt6(); break; case 7: bkpt7(); break; case 8: bkpt8(); break; case 9: bkpt9(); break; case 10: bkpt10(); break; case 11: bkpt11(); break; case 12: bkpt12(); break; case 13: bkpt13(); break; case 14: bkpt14(); break; case 15: bkpt15(); break; case 16: bkpt16(); break; case 17: bkpt17(); break; case 18: bkpt18(); break; case 19: bkpt19(); break; case 20: bkpt20(); break; case 21: bkpt21(); break; case 22: bkpt22(); break; case 23: bkpt23(); break; case 24: bkpt24(); break; case 25: bkpt25(); break; case 26: bkpt26(); break; case 27: bkpt27(); break; case 28: bkpt28(); break; case 29: bkpt29(); break; } System.out.println("Thread " + threadName + " You entered : " + s); if( s.compareTo( "quit" ) == 0 ) done = true; } } catch(Exception e) { System.out.println("WOOPS"); } } } }; thrd.setPriority(Thread.MAX_PRIORITY-1); thrd.start(); } } /********** test program **********/ public class MultiBreakpointsTest extends TestScaffold { ReferenceType targetClass; ThreadReference mainThread; EventRequestManager erm; static int nthreads; static int nhits; BreakpointRequest bkpts[]; int hits[]; MultiBreakpointsTest (String args[]) { super(args); bkpts = new BreakpointRequest[nthreads]; hits = new int[nthreads]; } public static void main(String[] args) throws Exception { String countStr = System.getProperty("nthreads"); if (countStr == null) { nthreads = 4; } else { nthreads = Integer.parseInt(countStr); } if ( nthreads > 30) { throw new RuntimeException("nthreads is greater than 30: " + nthreads); } countStr = System.getProperty("nhits"); if (countStr == null) { nhits = 100; } else { nhits = Integer.parseInt(countStr); } args = new String[] { "-J-Dnthreads=" + nthreads, "-J-Dnhits=" + nhits} ; new MultiBreakpointsTest(args).startTests(); } /********** event handlers **********/ public void breakpointReached(BreakpointEvent event) { BreakpointRequest req = (BreakpointRequest)event.request(); for ( int ii = 0; ii < nthreads; ii++) { if (req == bkpts[ii]) { println("Hit bkpt on thread: " +ii+ ": " + ++hits[ii]); break; } } } public BreakpointRequest setBreakpoint(String clsName, String methodName, String methodSignature) { ReferenceType rt = findReferenceType(clsName); if (rt == null) { rt = resumeToPrepareOf(clsName).referenceType(); } Method method = findMethod(rt, methodName, methodSignature); if (method == null) { throw new IllegalArgumentException("Bad method name/signature"); } BreakpointRequest bpr = erm.createBreakpointRequest(method.location()); bpr.setSuspendPolicy(EventRequest.SUSPEND_ALL); //bpr.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD); bpr.enable(); return bpr; } /********** test core **********/ protected void runTests() throws Exception { /* * Get to the top of main() * to determine targetClass and mainThread */ BreakpointEvent bpe = startToMain("MultiBreakpointsTarg"); targetClass = bpe.location().declaringType(); mainThread = bpe.thread(); erm = vm().eventRequestManager(); for (int ii = 0 ; ii < nthreads; ii++) { bkpts[ii] = setBreakpoint("MultiBreakpointsTarg", "bkpt" + ii, "()V"); } /* * resume the target listening for events */ listenUntilVMDisconnect(); for ( int ii = 0; ii < nthreads; ii++) { if (hits[ii] != nhits) { failure("FAILED: Expected " + nhits + " breakpoints for thread " + ii + " but only got " + hits[ii]); } } /* * deal with results of test * if anything has called failure("foo") testFailed will be true */ if (!testFailed) { println("MultiBreakpointsTest: passed"); } else { throw new Exception("MultiBreakpointsTest: failed"); } } }