| /* | |
| * Copyright (c) 2001, 2023, 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) { | |
| Thread threads[] = new Thread[numThreads]; | |
| for (int ii = 0; ii < numThreads; ii++) { | |
| threads[ii] = console(ii, numHits); | |
| } | |
| for (int ii = 0; ii < numThreads; ii++) { | |
| try { | |
| threads[ii].join(); | |
| } catch (InterruptedException ie) { | |
| throw new RuntimeException(ie); | |
| } | |
| } | |
| } | |
| 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() {} | |
| Thread 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 = DebuggeeWrapper.newThread(() -> { | |
| 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.setName(threadName); | |
| thrd.setPriority(Thread.MAX_PRIORITY-1); | |
| thrd.start(); | |
| return thrd; | |
| } | |
| } | |
| /********** 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[] { "-Dnthreads=" + nthreads, "-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"); | |
| } | |
| } | |
| } |