1 /*
2  * Copyright (c) 2019, 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 8219143
27  * @summary Tests that using the "stop in" threadid option will properly cause the
28  * breakpoint to only be triggered when hit in the specified thread.
29  *
30  * @library /test/lib
31  * @run compile -g JdbStopThreadidTest.java
32  * @run main/othervm JdbStopThreadidTest
33  */
34 
35 import jdk.test.lib.process.OutputAnalyzer;
36 import lib.jdb.Jdb;
37 import lib.jdb.JdbCommand;
38 import lib.jdb.JdbTest;
39 
40 import java.util.regex.*;
41 
42 class JdbStopThreadidTestTarg {
43     static Object lockObj = new Object();
44 
main(String[] args)45     public static void main(String[] args) {
46         test();
47     }
48 
test()49     private static void test() {
50         JdbStopThreadidTestTarg test = new JdbStopThreadidTestTarg();
51         MyThread myThread1 = test.new MyThread("MYTHREAD-1");
52         MyThread myThread2 = test.new MyThread("MYTHREAD-2");
53         MyThread myThread3 = test.new MyThread("MYTHREAD-3");
54 
55         synchronized (lockObj) {
56             myThread1.start();
57             myThread2.start();
58             myThread3.start();
59             // Wait for all threads to have started. Note they all block on lockObj after starting.
60             while (!myThread1.started || !myThread2.started || !myThread3.started) {
61                 try {
62                     Thread.sleep(50);
63                 } catch (InterruptedException e) {
64                 }
65             }
66             // Stop here so the test can setup the breakpoint in MYTHREAD-2
67             brkMethod();
68         }
69 
70         // Wait for all threads to finish before exiting
71         try {
72             myThread1.join();
73             myThread2.join();
74             myThread3.join();
75         } catch (InterruptedException e) {
76         }
77     }
78 
brkMethod()79     static void brkMethod() {
80     }
81 
print(Object obj)82     public static void print(Object obj) {
83         System.out.println(obj);
84     }
85 
86     class MyThread extends Thread {
87         volatile boolean started = false;
88 
MyThread(String name)89         public MyThread(String name) {
90             super(name);
91         }
92 
run()93         public void run() {
94             started = true;
95             synchronized (JdbStopThreadidTestTarg.lockObj) {
96             }
97             brkMethod();
98         }
99 
brkMethod()100         void brkMethod() {
101         }
102     }
103 }
104 
105 public class JdbStopThreadidTest extends JdbTest {
main(String argv[])106     public static void main(String argv[]) {
107         new JdbStopThreadidTest().run();
108     }
109 
JdbStopThreadidTest()110     private JdbStopThreadidTest() {
111         super(DEBUGGEE_CLASS);
112     }
113 
114     private static final String DEBUGGEE_CLASS = JdbStopThreadidTestTarg.class.getName();
115     private static final String DEBUGGEE_THREAD_CLASS = JdbStopThreadidTestTarg.class.getName() + "$MyThread";
116     private static Pattern threadidPattern = Pattern.compile("MyThread\\)(\\S+)\\s+MYTHREAD-2");
117 
118     @Override
runCases()119     protected void runCases() {
120         jdb.command(JdbCommand.stopIn(DEBUGGEE_CLASS, "brkMethod"));
121         jdb.command(JdbCommand.run().waitForPrompt("Breakpoint hit: \"thread=main\"", true));
122         jdb.command(JdbCommand.threads());
123 
124         // Find the threadid for MYTHREAD-2 in the "threads" command output
125         String output = jdb.getJdbOutput();
126         Matcher m = threadidPattern.matcher(output);
127         String threadid = null;
128         if (m.find()) {
129             threadid = m.group(1);
130         } else {
131             throw new RuntimeException("FAILED: Did not match threadid pattern.");
132         }
133 
134         // Setup a breakpoint in MYTHREAD-2.
135         jdb.command(JdbCommand.stopInThreadid(DEBUGGEE_THREAD_CLASS, "brkMethod", threadid));
136 
137         // Continue until MYTHREAD-2 breakpoint is hit. If we hit any other breakpoint before
138         // then (we aren't suppose to), then this test will fail.
139         jdb.command(JdbCommand.cont().waitForPrompt("Breakpoint hit: \"thread=MYTHREAD-2\", \\S+MyThread.brkMethod", true));
140         // Continue until the application exits. Once again, hitting a breakpoint will cause
141         // a failure because we are not suppose to hit one.
142         jdb.contToExit(1);
143         new OutputAnalyzer(getJdbOutput()).shouldContain(Jdb.APPLICATION_EXIT);
144     }
145 }
146