mirror of
https://github.com/openjdk/jdk.git
synced 2026-05-12 14:39:49 +00:00
8219143: jdb should support breakpoint thread filters
Add thread filter to stop command. Reviewed-by: sspitsyn, amenkov
This commit is contained in:
parent
ab5cedabe1
commit
b0eedd125f
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 2019, 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
|
||||
@ -44,20 +44,24 @@ class BreakpointSpec extends EventRequestSpec {
|
||||
String methodId;
|
||||
List<String> methodArgs;
|
||||
int lineNumber;
|
||||
ThreadReference threadFilter; /* Thread to break in. null if global breakpoint. */
|
||||
public static final String locationTokenDelimiter = ":( \t\n\r";
|
||||
|
||||
BreakpointSpec(ReferenceTypeSpec refSpec, int lineNumber) {
|
||||
BreakpointSpec(ReferenceTypeSpec refSpec, int lineNumber, ThreadReference threadFilter) {
|
||||
super(refSpec);
|
||||
this.methodId = null;
|
||||
this.methodArgs = null;
|
||||
this.lineNumber = lineNumber;
|
||||
this.threadFilter = threadFilter;
|
||||
}
|
||||
|
||||
BreakpointSpec(ReferenceTypeSpec refSpec, String methodId,
|
||||
BreakpointSpec(ReferenceTypeSpec refSpec, String methodId, ThreadReference threadFilter,
|
||||
List<String> methodArgs) throws MalformedMemberNameException {
|
||||
super(refSpec);
|
||||
this.methodId = methodId;
|
||||
this.methodArgs = methodArgs;
|
||||
this.lineNumber = 0;
|
||||
this.threadFilter = threadFilter;
|
||||
if (!isValidMethodName(methodId)) {
|
||||
throw new MalformedMemberNameException(methodId);
|
||||
}
|
||||
@ -78,8 +82,11 @@ class BreakpointSpec extends EventRequestSpec {
|
||||
throw new InvalidTypeException();
|
||||
}
|
||||
EventRequestManager em = refType.virtualMachine().eventRequestManager();
|
||||
EventRequest bp = em.createBreakpointRequest(location);
|
||||
BreakpointRequest bp = em.createBreakpointRequest(location);
|
||||
bp.setSuspendPolicy(suspendPolicy);
|
||||
if (threadFilter != null) {
|
||||
bp.addThreadFilter(threadFilter);
|
||||
}
|
||||
bp.enable();
|
||||
return bp;
|
||||
}
|
||||
@ -104,7 +111,8 @@ class BreakpointSpec extends EventRequestSpec {
|
||||
public int hashCode() {
|
||||
return refSpec.hashCode() + lineNumber +
|
||||
((methodId != null) ? methodId.hashCode() : 0) +
|
||||
((methodArgs != null) ? methodArgs.hashCode() : 0);
|
||||
((methodArgs != null) ? methodArgs.hashCode() : 0) +
|
||||
((threadFilter != null) ? threadFilter.hashCode() : 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -118,6 +126,9 @@ class BreakpointSpec extends EventRequestSpec {
|
||||
((methodArgs != null) ?
|
||||
methodArgs.equals(breakpoint.methodArgs)
|
||||
: methodArgs == breakpoint.methodArgs) &&
|
||||
((threadFilter != null) ?
|
||||
threadFilter.equals(breakpoint.threadFilter)
|
||||
: threadFilter == breakpoint.threadFilter) &&
|
||||
refSpec.equals(breakpoint.refSpec) &&
|
||||
(lineNumber == breakpoint.lineNumber);
|
||||
} else {
|
||||
|
||||
@ -1037,16 +1037,16 @@ class Commands {
|
||||
}
|
||||
|
||||
|
||||
private void printBreakpointCommandUsage(String atForm, String inForm) {
|
||||
MessageOutput.println("printbreakpointcommandusage",
|
||||
new Object [] {atForm, inForm});
|
||||
private void printBreakpointCommandUsage(String usageMessage) {
|
||||
MessageOutput.println(usageMessage);
|
||||
}
|
||||
|
||||
protected BreakpointSpec parseBreakpointSpec(StringTokenizer t,
|
||||
String atForm, String inForm) {
|
||||
protected BreakpointSpec parseBreakpointSpec(StringTokenizer t, String next_token,
|
||||
ThreadReference threadFilter,
|
||||
String usageMessage) {
|
||||
BreakpointSpec breakpoint = null;
|
||||
try {
|
||||
String token = t.nextToken(":( \t\n\r");
|
||||
String token = next_token;
|
||||
|
||||
// We can't use hasMoreTokens here because it will cause any leading
|
||||
// paren to be lost.
|
||||
@ -1064,16 +1064,24 @@ class Commands {
|
||||
|
||||
NumberFormat nf = NumberFormat.getNumberInstance();
|
||||
nf.setParseIntegerOnly(true);
|
||||
Number n = nf.parse(lineToken);
|
||||
Number n;
|
||||
try {
|
||||
n = nf.parse(lineToken);
|
||||
} catch (java.text.ParseException pe) {
|
||||
MessageOutput.println("Invalid line number specified");
|
||||
printBreakpointCommandUsage(usageMessage);
|
||||
return null;
|
||||
}
|
||||
int lineNumber = n.intValue();
|
||||
|
||||
if (t.hasMoreTokens()) {
|
||||
printBreakpointCommandUsage(atForm, inForm);
|
||||
MessageOutput.println("Extra tokens after breakpoint location");
|
||||
printBreakpointCommandUsage(usageMessage);
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
breakpoint = Env.specList.createBreakpoint(classId,
|
||||
lineNumber);
|
||||
lineNumber, threadFilter);
|
||||
} catch (ClassNotFoundException exc) {
|
||||
MessageOutput.println("is not a valid class name", classId);
|
||||
}
|
||||
@ -1082,7 +1090,8 @@ class Commands {
|
||||
int idot = token.lastIndexOf('.');
|
||||
if ( (idot <= 0) || /* No dot or dot in first char */
|
||||
(idot >= token.length() - 1) ) { /* dot in last char */
|
||||
printBreakpointCommandUsage(atForm, inForm);
|
||||
MessageOutput.println("Invalid <class>.<method_name> specification");
|
||||
printBreakpointCommandUsage(usageMessage);
|
||||
return null;
|
||||
}
|
||||
String methodName = token.substring(idot + 1);
|
||||
@ -1090,9 +1099,9 @@ class Commands {
|
||||
List<String> argumentList = null;
|
||||
if (rest != null) {
|
||||
if (!rest.startsWith("(") || !rest.endsWith(")")) {
|
||||
MessageOutput.println("Invalid method specification:",
|
||||
MessageOutput.println("Invalid <method_name> specification:",
|
||||
methodName + rest);
|
||||
printBreakpointCommandUsage(atForm, inForm);
|
||||
printBreakpointCommandUsage(usageMessage);
|
||||
return null;
|
||||
}
|
||||
// Trim the parens
|
||||
@ -1107,6 +1116,7 @@ class Commands {
|
||||
try {
|
||||
breakpoint = Env.specList.createBreakpoint(classId,
|
||||
methodName,
|
||||
threadFilter,
|
||||
argumentList);
|
||||
} catch (MalformedMemberNameException exc) {
|
||||
MessageOutput.println("is not a valid method name", methodName);
|
||||
@ -1115,7 +1125,7 @@ class Commands {
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
printBreakpointCommandUsage(atForm, inForm);
|
||||
printBreakpointCommandUsage(usageMessage);
|
||||
return null;
|
||||
}
|
||||
return breakpoint;
|
||||
@ -1145,33 +1155,74 @@ class Commands {
|
||||
}
|
||||
|
||||
void commandStop(StringTokenizer t) {
|
||||
String atIn;
|
||||
byte suspendPolicy = EventRequest.SUSPEND_ALL;
|
||||
ThreadReference threadFilter = null;
|
||||
|
||||
if (t.hasMoreTokens()) {
|
||||
atIn = t.nextToken();
|
||||
if (atIn.equals("go") && t.hasMoreTokens()) {
|
||||
suspendPolicy = EventRequest.SUSPEND_NONE;
|
||||
atIn = t.nextToken();
|
||||
} else if (atIn.equals("thread") && t.hasMoreTokens()) {
|
||||
suspendPolicy = EventRequest.SUSPEND_EVENT_THREAD;
|
||||
atIn = t.nextToken();
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Allowed syntax:
|
||||
* stop [go|thread] [<thread_id>] <at|in> <location>
|
||||
* If no options are given, the current list of breakpoints is printed.
|
||||
* If "go" is specified, then immediately resume after stopping. No threads are suspended.
|
||||
* If "thread" is specified, then only suspend the thread we stop in.
|
||||
* If neither "go" nor "thread" are specified, then suspend all threads.
|
||||
* If an integer <thread_id> is specified, then only stop in the specified thread.
|
||||
* <location> can either be a line number or a method:
|
||||
* - <class id>:<line>
|
||||
* - <class id>.<method>[(argument_type,...)]
|
||||
*/
|
||||
|
||||
if (!t.hasMoreTokens()) {
|
||||
listBreakpoints();
|
||||
return;
|
||||
}
|
||||
|
||||
BreakpointSpec spec = parseBreakpointSpec(t, "stop at", "stop in");
|
||||
if (spec != null) {
|
||||
// Enforcement of "at" vs. "in". The distinction is really
|
||||
// unnecessary and we should consider not checking for this
|
||||
// (and making "at" and "in" optional).
|
||||
if (atIn.equals("at") && spec.isMethodBreakpoint()) {
|
||||
MessageOutput.println("Use stop at to set a breakpoint at a line number");
|
||||
printBreakpointCommandUsage("stop at", "stop in");
|
||||
String token = t.nextToken();
|
||||
|
||||
/* Check for "go" or "thread" modifiers. */
|
||||
if (token.equals("go") && t.hasMoreTokens()) {
|
||||
suspendPolicy = EventRequest.SUSPEND_NONE;
|
||||
token = t.nextToken();
|
||||
} else if (token.equals("thread") && t.hasMoreTokens()) {
|
||||
suspendPolicy = EventRequest.SUSPEND_EVENT_THREAD;
|
||||
token = t.nextToken();
|
||||
}
|
||||
|
||||
/* Handle <thread_id> modifier. */
|
||||
if (!token.equals("at") && !token.equals("in")) {
|
||||
Long threadid;
|
||||
try {
|
||||
threadid = Long.decode(token);
|
||||
} catch (NumberFormatException nfe) {
|
||||
MessageOutput.println("Expected at, in, or an integer <thread_id>:", token);
|
||||
printBreakpointCommandUsage("printstopcommandusage");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
ThreadInfo threadInfo = ThreadInfo.getThreadInfo(token);
|
||||
if (threadInfo == null) {
|
||||
MessageOutput.println("Invalid <thread_id>:", token);
|
||||
return;
|
||||
}
|
||||
threadFilter = threadInfo.getThread();
|
||||
token = t.nextToken(BreakpointSpec.locationTokenDelimiter);
|
||||
} catch (VMNotConnectedException vmnce) {
|
||||
MessageOutput.println("<thread_id> option not valid until the VM is started with the run command");
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Make sure "at" or "in" comes next. */
|
||||
if (!token.equals("at") && !token.equals("in")) {
|
||||
MessageOutput.println("Missing at or in");
|
||||
printBreakpointCommandUsage("printstopcommandusage");
|
||||
return;
|
||||
}
|
||||
|
||||
token = t.nextToken(BreakpointSpec.locationTokenDelimiter);
|
||||
|
||||
BreakpointSpec spec = parseBreakpointSpec(t, token, threadFilter, "printstopcommandusage");
|
||||
if (spec != null) {
|
||||
spec.suspendPolicy = suspendPolicy;
|
||||
resolveNow(spec);
|
||||
}
|
||||
@ -1183,7 +1234,8 @@ class Commands {
|
||||
return;
|
||||
}
|
||||
|
||||
BreakpointSpec spec = parseBreakpointSpec(t, "clear", "clear");
|
||||
String token = t.nextToken(BreakpointSpec.locationTokenDelimiter);
|
||||
BreakpointSpec spec = parseBreakpointSpec(t, token, null, "printclearcommandusage");
|
||||
if (spec != null) {
|
||||
if (Env.specList.delete(spec)) {
|
||||
MessageOutput.println("Removed:", spec.toString());
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 2019, 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
|
||||
@ -36,6 +36,7 @@ package com.sun.tools.example.debug.tty;
|
||||
|
||||
import com.sun.jdi.request.EventRequest;
|
||||
import com.sun.jdi.event.ClassPrepareEvent;
|
||||
import com.sun.jdi.ThreadReference;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@ -108,21 +109,21 @@ class EventRequestSpecList {
|
||||
}
|
||||
}
|
||||
|
||||
BreakpointSpec createBreakpoint(String classPattern, int line)
|
||||
BreakpointSpec createBreakpoint(String classPattern, int line, ThreadReference threadFilter)
|
||||
throws ClassNotFoundException {
|
||||
ReferenceTypeSpec refSpec =
|
||||
new PatternReferenceTypeSpec(classPattern);
|
||||
return new BreakpointSpec(refSpec, line);
|
||||
return new BreakpointSpec(refSpec, line, threadFilter);
|
||||
}
|
||||
|
||||
BreakpointSpec createBreakpoint(String classPattern,
|
||||
String methodId,
|
||||
String methodId, ThreadReference threadFilter,
|
||||
List<String> methodArgs)
|
||||
throws MalformedMemberNameException,
|
||||
ClassNotFoundException {
|
||||
ReferenceTypeSpec refSpec =
|
||||
new PatternReferenceTypeSpec(classPattern);
|
||||
return new BreakpointSpec(refSpec, methodId, methodArgs);
|
||||
return new BreakpointSpec(refSpec, methodId, threadFilter, methodArgs);
|
||||
}
|
||||
|
||||
EventRequestSpec createExceptionCatch(String classPattern,
|
||||
|
||||
@ -120,12 +120,14 @@ public class TTYResources extends java.util.ListResourceBundle {
|
||||
{"Exception occurred caught", "Exception occurred: {0} (to be caught at: {1})"},
|
||||
{"Exception occurred uncaught", "Exception occurred: {0} (uncaught)"},
|
||||
{"Exceptions caught:", "Break when these exceptions occur:"},
|
||||
{"Expected at, in, or an integer <thread_id>:", "Expected \"at\", \"in\", or an integer <thread_id>: {0}"},
|
||||
{"expr is null", "{0} = null"},
|
||||
{"expr is value", "{0} = {1}"},
|
||||
{"expr is value <collected>", " {0} = {1} <collected>"},
|
||||
{"Expression cannot be void", "Expression cannot be void"},
|
||||
{"Expression must evaluate to an object", "Expression must evaluate to an object"},
|
||||
{"extends:", "extends: {0}"},
|
||||
{"Extra tokens after breakpoint location", "Extra tokens after breakpoint location"},
|
||||
{"Failed reading output", "Failed reading output of child java interpreter."},
|
||||
{"Fatal error", "Fatal error:"},
|
||||
{"Field access encountered before after", "Field ({0}) is {1}, will be {2}: "},
|
||||
@ -154,11 +156,14 @@ public class TTYResources extends java.util.ListResourceBundle {
|
||||
{"Invalid connect type", "Invalid connect type"},
|
||||
{"Invalid consecutive invocations", "Invalid consecutive invocations"},
|
||||
{"Invalid exception object", "Invalid exception object"},
|
||||
{"Invalid method specification:", "Invalid method specification: {0}"},
|
||||
{"Invalid line number specified", "Invalid line number specified"},
|
||||
{"Invalid <method_name> specification:", "Invalid <method_name> specification: {0}"},
|
||||
{"Invalid option on class command", "Invalid option on class command"},
|
||||
{"invalid option", "invalid option: {0}"},
|
||||
{"Invalid thread status.", "Invalid thread status."},
|
||||
{"Invalid <thread_id>:", "Invalid <thread_id>: {0}"},
|
||||
{"Invalid transport name:", "Invalid transport name: {0}"},
|
||||
{"Invalid <class>.<method_name> specification", "Invalid <class>.<method_name> specification"},
|
||||
{"I/O exception occurred:", "I/O Exception occurred: {0}"},
|
||||
{"is an ambiguous method name in", "\"{0}\" is an ambiguous method name in \"{1}\""},
|
||||
{"is an invalid line number for", "{0,number,integer} is an invalid line number for {1}"},
|
||||
@ -191,6 +196,7 @@ public class TTYResources extends java.util.ListResourceBundle {
|
||||
{"Method exitedValue:", "Method exited: return value = {0}, "},
|
||||
{"Method is overloaded; specify arguments", "Method {0} is overloaded; specify arguments"},
|
||||
{"minus version", "This is {0} version {1,number,integer}.{2,number,integer} (Java SE version {3})"},
|
||||
{"Missing at or in", "Missing \"at\" or \"in\""},
|
||||
{"Monitor information for thread", "Monitor information for thread {0}:"},
|
||||
{"Monitor information for expr", "Monitor information for {0} ({1}):"},
|
||||
{"More than one class named", "More than one class named: ''{0}''"},
|
||||
@ -241,7 +247,18 @@ public class TTYResources extends java.util.ListResourceBundle {
|
||||
{"Owned by:", " Owned by: {0}, entry count: {1,number,integer}"},
|
||||
{"Owned monitor:", " Owned monitor: {0}"},
|
||||
{"Parse exception:", "Parse Exception: {0}"},
|
||||
{"printbreakpointcommandusage", "Usage: {0} <class>:<line_number> or\n {1} <class>.<method_name>[(argument_type,...)]"},
|
||||
{"printclearcommandusage", "Usage clear <class>:<line_number> or\n clear <class>.<method_name>[(argument_type,...)]"},
|
||||
{"printstopcommandusage",
|
||||
"Usage: stop [go|thread] [<thread_id>] <at|in> <location>\n" +
|
||||
" If \"go\" is specified, immediately resume after stopping\n" +
|
||||
" If \"thread\" is specified, only suspend the thread we stop in\n" +
|
||||
" If neither \"go\" nor \"thread\" are specified, suspend all threads\n" +
|
||||
" If an integer <thread_id> is specified, only stop in the specified thread\n" +
|
||||
" \"at\" and \"in\" have the same meaning\n" +
|
||||
" <location> can either be a line number or a method:\n" +
|
||||
" <class_id>:<line_number>\n" +
|
||||
" <class_id>.<method>[(argument_type,...)]"
|
||||
},
|
||||
{"Removed:", "Removed: {0}"},
|
||||
{"Requested stack frame is no longer active:", "Requested stack frame is no longer active: {0,number,integer}"},
|
||||
{"run <args> command is valid only with launched VMs", "'run <args>' command is valid only with launched VMs"},
|
||||
@ -292,6 +309,8 @@ public class TTYResources extends java.util.ListResourceBundle {
|
||||
{"Thread not suspended", "Thread not suspended"},
|
||||
{"thread group number description name", "{0,number,integer}. {1} {2}"},
|
||||
{"Threadgroup name not specified.", "Threadgroup name not specified."},
|
||||
{"<thread_id> option not valid until the VM is started with the run command",
|
||||
"<thread_id> option not valid until the VM is started with the run command"},
|
||||
{"Threads must be suspended", "Threads must be suspended"},
|
||||
{"trace method exit in effect for", "trace method exit in effect for {0}"},
|
||||
{"trace method exits in effect", "trace method exits in effect"},
|
||||
@ -318,7 +337,6 @@ public class TTYResources extends java.util.ListResourceBundle {
|
||||
{"Usage: unmonitor <monitor#>", "Usage: unmonitor <monitor#>"},
|
||||
{"Usage: up [n frames]", "Usage: up [n frames]"},
|
||||
{"Use java minus X to see", "Use 'java -X' to see the available non-standard options"},
|
||||
{"Use stop at to set a breakpoint at a line number", "Use 'stop at' to set a breakpoint at a line number"},
|
||||
{"VM already running. use cont to continue after events.", "VM already running. Use 'cont' to continue after events."},
|
||||
{"VM Started:", "VM Started: "},
|
||||
{"vmstartexception", "VM start exception: {0}"},
|
||||
@ -357,9 +375,17 @@ public class TTYResources extends java.util.ListResourceBundle {
|
||||
"threadgroups -- list threadgroups\n" +
|
||||
"threadgroup <name> -- set current threadgroup\n" +
|
||||
"\n" +
|
||||
"stop in <class id>.<method>[(argument_type,...)]\n" +
|
||||
" -- set a breakpoint in a method\n" +
|
||||
"stop at <class id>:<line> -- set a breakpoint at a line\n" +
|
||||
"stop [go|thread] [<thread_id>] <at|in> <location>\n" +
|
||||
" -- set a breakpoint\n" +
|
||||
" -- if no options are given, the current list of breakpoints is printed\n" +
|
||||
" -- if \"go\" is specified, immediately resume after stopping\n" +
|
||||
" -- if \"thread\" is specified, only suspend the thread we stop in\n" +
|
||||
" -- if neither \"go\" nor \"thread\" are specified, suspend all threads\n" +
|
||||
" -- if an integer <thread_id> is specified, only stop in the specified thread\n" +
|
||||
" -- \"at\" and \"in\" have the same meaning\n" +
|
||||
" -- <location> can either be a line number or a method:\n" +
|
||||
" -- <class_id>:<line_number>\n" +
|
||||
" -- <class_id>.<method>[(argument_type,...)]\n" +
|
||||
"clear <class id>.<method>[(argument_type,...)]\n" +
|
||||
" -- clear a breakpoint in a method\n" +
|
||||
"clear <class id>:<line> -- clear a breakpoint at a line\n" +
|
||||
@ -412,7 +438,7 @@ public class TTYResources extends java.util.ListResourceBundle {
|
||||
"<n> <command> -- repeat command n times\n" +
|
||||
"# <command> -- discard (no-op)\n" +
|
||||
"help (or ?) -- list commands\n" +
|
||||
"dbgtrace [flag] -- same as dbgtrace command line option" +
|
||||
"dbgtrace [flag] -- same as dbgtrace command line option\n" +
|
||||
"version -- print version information\n" +
|
||||
"exit (or quit) -- exit debugger\n" +
|
||||
"\n" +
|
||||
|
||||
143
test/jdk/com/sun/jdi/JdbStopThreadidTest.java
Normal file
143
test/jdk/com/sun/jdi/JdbStopThreadidTest.java
Normal file
@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 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 8219143
|
||||
* @summary Tests that using the "stop in" threadid option will properly cause the
|
||||
* breakpoint to only be triggered when hit in the specified thread.
|
||||
*
|
||||
* @library /test/lib
|
||||
* @run compile -g JdbStopThreadidTest.java
|
||||
* @run main/othervm JdbStopThreadidTest
|
||||
*/
|
||||
|
||||
import lib.jdb.Jdb;
|
||||
import lib.jdb.JdbCommand;
|
||||
import lib.jdb.JdbTest;
|
||||
|
||||
import java.util.regex.*;
|
||||
|
||||
class JdbStopThreadidTestTarg {
|
||||
static Object lockObj = new Object();
|
||||
|
||||
public static void main(String[] args) {
|
||||
test();
|
||||
}
|
||||
|
||||
private static void test() {
|
||||
JdbStopThreadidTestTarg test = new JdbStopThreadidTestTarg();
|
||||
MyThread myThread1 = test.new MyThread("MYTHREAD-1");
|
||||
MyThread myThread2 = test.new MyThread("MYTHREAD-2");
|
||||
MyThread myThread3 = test.new MyThread("MYTHREAD-3");
|
||||
|
||||
synchronized (lockObj) {
|
||||
myThread1.start();
|
||||
myThread2.start();
|
||||
myThread3.start();
|
||||
// Wait for all threads to have started. Note they all block on lockObj after starting.
|
||||
while (!myThread1.started || !myThread2.started || !myThread3.started) {
|
||||
try {
|
||||
Thread.sleep(50);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
// Stop here so the test can setup the breakpoint in MYTHREAD-2
|
||||
brkMethod();
|
||||
}
|
||||
|
||||
// Wait for all threads to finish before exiting
|
||||
try {
|
||||
myThread1.join();
|
||||
myThread2.join();
|
||||
myThread3.join();
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
}
|
||||
|
||||
static void brkMethod() {
|
||||
}
|
||||
|
||||
public static void print(Object obj) {
|
||||
System.out.println(obj);
|
||||
}
|
||||
|
||||
class MyThread extends Thread {
|
||||
volatile boolean started = false;
|
||||
|
||||
public MyThread(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
public void run() {
|
||||
started = true;
|
||||
synchronized (JdbStopThreadidTestTarg.lockObj) {
|
||||
}
|
||||
brkMethod();
|
||||
}
|
||||
|
||||
void brkMethod() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class JdbStopThreadidTest extends JdbTest {
|
||||
public static void main(String argv[]) {
|
||||
new JdbStopThreadidTest().run();
|
||||
}
|
||||
|
||||
private JdbStopThreadidTest() {
|
||||
super(DEBUGGEE_CLASS);
|
||||
}
|
||||
|
||||
private static final String DEBUGGEE_CLASS = JdbStopThreadidTestTarg.class.getName();
|
||||
private static final String DEBUGGEE_THREAD_CLASS = JdbStopThreadidTestTarg.class.getName() + "$MyThread";
|
||||
private static Pattern threadidPattern = Pattern.compile("MyThread\\)(\\S+)\\s+MYTHREAD-2");
|
||||
|
||||
@Override
|
||||
protected void runCases() {
|
||||
jdb.command(JdbCommand.stopIn(DEBUGGEE_CLASS, "brkMethod"));
|
||||
jdb.command(JdbCommand.run().waitForPrompt("Breakpoint hit: \"thread=main\"", true));
|
||||
jdb.command(JdbCommand.threads());
|
||||
|
||||
// Find the threadid for MYTHREAD-2 in the "threads" command output
|
||||
String output = jdb.getJdbOutput();
|
||||
Matcher m = threadidPattern.matcher(output);
|
||||
String threadid = null;
|
||||
if (m.find()) {
|
||||
threadid = m.group(1);
|
||||
} else {
|
||||
throw new RuntimeException("FAILED: Did not match threadid pattern.");
|
||||
}
|
||||
|
||||
// Setup a breakpoint in MYTHREAD-2.
|
||||
jdb.command(JdbCommand.stopInThreadid(DEBUGGEE_THREAD_CLASS, "brkMethod", threadid));
|
||||
|
||||
// Continue until MYTHREAD-2 breakpoint is hit. If we hit any other breakpoint before
|
||||
// then (we aren't suppose to), then this test will fail.
|
||||
jdb.command(JdbCommand.cont().waitForPrompt("Breakpoint hit: \"thread=MYTHREAD-2\", \\S+MyThread.brkMethod", true));
|
||||
// Continue until the application exits. Once again, hitting a breakpoint will cause
|
||||
// a failure because we are not suppose to hit one.
|
||||
jdb.command(JdbCommand.cont().waitForPrompt(Jdb.APPLICATION_EXIT, true));
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 2019, 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
|
||||
@ -162,6 +162,9 @@ public class JdbCommand {
|
||||
public static JdbCommand stopIn(String targetClass, String methodName) {
|
||||
return new JdbCommand("stop in " + targetClass + "." + methodName);
|
||||
}
|
||||
public static JdbCommand stopInThreadid(String targetClass, String methodName, String threadid) {
|
||||
return new JdbCommand("stop " + threadid + " in " + targetClass + "." + methodName);
|
||||
}
|
||||
public static JdbCommand thread(int threadNumber) {
|
||||
return new JdbCommand("thread " + threadNumber);
|
||||
}
|
||||
@ -226,6 +229,10 @@ public class JdbCommand {
|
||||
return new JdbCommand("methods " + classId);
|
||||
}
|
||||
|
||||
public static JdbCommand threads() {
|
||||
return new JdbCommand("threads");
|
||||
}
|
||||
|
||||
// trace [go] methods [thread]
|
||||
// -- trace method entries and exits.
|
||||
// -- All threads are suspended unless 'go' is specified
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user