This commit is contained in:
Alejandro Murillo 2016-06-10 15:13:40 -07:00
commit b6cad8150e
10 changed files with 342 additions and 124 deletions

View File

@ -25,6 +25,7 @@
package sun.tools.common;
import java.lang.reflect.Module;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collection;
@ -45,13 +46,10 @@ import sun.jvmstat.monitor.VmIdentifier;
* the process identifiers.
*/
public class ProcessArgumentMatcher {
private String excludeCls;
private String matchClass = null;
private String singlePid = null;
private boolean matchAll = false;
private String matchClass;
private String singlePid;
public ProcessArgumentMatcher(String pidArg, Class<?> excludeClass) {
excludeCls = excludeClass.getName();
public ProcessArgumentMatcher(String pidArg) {
if (pidArg == null || pidArg.isEmpty()) {
throw new IllegalArgumentException("Pid string is invalid");
}
@ -60,9 +58,7 @@ public class ProcessArgumentMatcher {
}
try {
long pid = Long.parseLong(pidArg);
if (pid == 0) {
matchAll = true;
} else {
if (pid != 0) {
singlePid = String.valueOf(pid);
}
} catch (NumberFormatException nfe) {
@ -70,7 +66,18 @@ public class ProcessArgumentMatcher {
}
}
private boolean check(VirtualMachineDescriptor vmd) {
private static String getExcludeStringFrom(Class<?> excludeClass) {
if (excludeClass == null) {
return "";
}
Module m = excludeClass.getModule();
if (m.isNamed()) {
return m.getName() + "/" + excludeClass.getName();
}
return excludeClass.getName();
}
private static boolean check(VirtualMachineDescriptor vmd, String excludeClass, String partialMatch) {
String mainClass = null;
try {
VmIdentifier vmId = new VmIdentifier(vmd.id());
@ -87,42 +94,55 @@ public class ProcessArgumentMatcher {
// Handle this gracefully....
return false;
} catch (MonitorException | URISyntaxException e) {
if (e.getMessage() != null) {
System.err.println(e.getMessage());
} else {
Throwable cause = e.getCause();
if ((cause != null) && (cause.getMessage() != null)) {
System.err.println(cause.getMessage());
} else {
e.printStackTrace();
}
}
return false;
}
if (mainClass.equals(excludeCls)) {
if (excludeClass != null && mainClass.equals(excludeClass)) {
return false;
}
if (partialMatch != null && mainClass.indexOf(partialMatch) == -1) {
return false;
}
if (matchAll || mainClass.indexOf(matchClass) != -1) {
return true;
}
return false;
}
public Collection<String> getPids() {
Collection<String> pids = new ArrayList<>();
if (singlePid != null) {
pids.add(singlePid);
return pids;
}
private static Collection<VirtualMachineDescriptor> getSingleVMD(String pid) {
Collection<VirtualMachineDescriptor> vids = new ArrayList<>();
List<VirtualMachineDescriptor> vmds = VirtualMachine.list();
for (VirtualMachineDescriptor vmd : vmds) {
if (check(vmd)) {
pids.add(vmd.id());
if (check(vmd, null, null)) {
if (pid.equals(vmd.id())) {
vids.add(vmd);
}
}
return pids;
}
return vids;
}
private static Collection<VirtualMachineDescriptor> getVMDs(Class<?> excludeClass, String partialMatch) {
String excludeCls = getExcludeStringFrom(excludeClass);
Collection<VirtualMachineDescriptor> vids = new ArrayList<>();
List<VirtualMachineDescriptor> vmds = VirtualMachine.list();
for (VirtualMachineDescriptor vmd : vmds) {
if (check(vmd, excludeCls, partialMatch)) {
vids.add(vmd);
}
}
return vids;
}
public Collection<VirtualMachineDescriptor> getVirtualMachineDescriptors(Class<?> excludeClass) {
if (singlePid != null) {
return getSingleVMD(singlePid);
} else {
return getVMDs(excludeClass, matchClass);
}
}
public Collection<VirtualMachineDescriptor> getVirtualMachineDescriptors() {
return this.getVirtualMachineDescriptors(null);
}
}

View File

@ -45,6 +45,8 @@ class Arguments {
public Arguments(String[] args) {
if (args.length == 0 || args[0].equals("-l")) {
listProcesses = true;
/* list all processes */
processString = "0";
return;
}

View File

@ -65,36 +65,37 @@ public class JCmd {
System.exit(1);
}
ProcessArgumentMatcher ap = null;
try {
ap = new ProcessArgumentMatcher(arg.getProcessString());
} catch (IllegalArgumentException iae) {
System.err.println("Invalid pid '" + arg.getProcessString() + "' specified");
System.exit(1);
}
if (arg.isListProcesses()) {
List<VirtualMachineDescriptor> vmds = VirtualMachine.list();
for (VirtualMachineDescriptor vmd : vmds) {
for (VirtualMachineDescriptor vmd : ap.getVirtualMachineDescriptors(/* include jcmd in listing */)) {
System.out.println(vmd.id() + " " + vmd.displayName());
}
System.exit(0);
}
Collection<String> pids = Collections.emptyList();
try {
ProcessArgumentMatcher ap = new ProcessArgumentMatcher(arg.getProcessString(), JCmd.class);
pids = ap.getPids();
} catch (IllegalArgumentException iae) {
System.err.println("Invalid pid specified");
System.exit(1);
}
if (pids.isEmpty()) {
Collection<VirtualMachineDescriptor> vids = ap.getVirtualMachineDescriptors(JCmd.class);
if (vids.isEmpty()) {
System.err.println("Could not find any processes matching : '"
+ arg.getProcessString() + "'");
System.exit(1);
}
boolean success = true;
for (String pid : pids) {
System.out.println(pid + ":");
for (VirtualMachineDescriptor vid : vids) {
System.out.println(vid.id() + ":");
if (arg.isListCounters()) {
listCounters(pid);
listCounters(vid.id());
} else {
try {
executeCommandForPid(pid, arg.getCommand());
executeCommandForPid(vid.id(), arg.getCommand());
} catch(AttachOperationFailedException ex) {
System.err.println(ex.getMessage());
success = false;

View File

@ -30,6 +30,7 @@ import java.io.InputStream;
import java.util.Collection;
import com.sun.tools.attach.VirtualMachine;
import com.sun.tools.attach.VirtualMachineDescriptor;
import sun.tools.attach.HotSpotVirtualMachine;
import sun.tools.common.ProcessArgumentMatcher;
@ -50,6 +51,7 @@ final public class JInfo {
boolean doFlag = false;
boolean doFlags = false;
boolean doSysprops = false;
int flag = -1;
// Parse the options (arguments starting with "-" )
int optionCount = 0;
@ -67,65 +69,64 @@ final public class JInfo {
if (arg.equals("-flag")) {
doFlag = true;
continue;
// Consume the flag
if (optionCount < args.length) {
flag = optionCount++;
break;
}
usage(1);
}
if (arg.equals("-flags")) {
doFlags = true;
continue;
break;
}
if (arg.equals("-sysprops")) {
doSysprops = true;
continue;
break;
}
}
// Next we check the parameter count. -flag allows extra parameters
int paramCount = args.length - optionCount;
if ((doFlag && paramCount != 2) || ((!doFlag && paramCount != 1))) {
if (paramCount != 1) {
usage(1);
}
if (!doFlag && !doFlags && !doSysprops) {
// Print flags and sysporps if no options given
ProcessArgumentMatcher ap = new ProcessArgumentMatcher(args[optionCount], JInfo.class);
Collection<String> pids = ap.getPids();
for (String pid : pids) {
if (pids.size() > 1) {
System.out.println("Pid:" + pid);
}
sysprops(pid);
System.out.println();
flags(pid);
System.out.println();
commandLine(pid);
}
String parg = args[optionCount];
ProcessArgumentMatcher ap = new ProcessArgumentMatcher(parg);
Collection<VirtualMachineDescriptor> vids = ap.getVirtualMachineDescriptors(JInfo.class);
if (vids.isEmpty()) {
System.err.println("Could not find any processes matching : '" + parg + "'");
System.exit(1);
}
for (VirtualMachineDescriptor vid : vids) {
if (vids.size() > 1) {
System.out.println("Pid:" + vid.id());
}
if (!doFlag && !doFlags && !doSysprops) {
// Print flags and sysporps if no options given
sysprops(vid.id());
System.out.println();
flags(vid.id());
System.out.println();
commandLine(vid.id());
}
if (doFlag) {
ProcessArgumentMatcher ap = new ProcessArgumentMatcher(args[optionCount+1], JInfo.class);
Collection<String> pids = ap.getPids();
for (String pid : pids) {
if (pids.size() > 1) {
System.out.println("Pid:" + pid);
if (flag < 0) {
System.err.println("Missing flag");
usage(1);
}
flag(pid, args[optionCount]);
}
}
else if (doFlags || doSysprops) {
ProcessArgumentMatcher ap = new ProcessArgumentMatcher(args[optionCount], JInfo.class);
Collection<String> pids = ap.getPids();
for (String pid : pids) {
if (pids.size() > 1) {
System.out.println("Pid:" + pid);
flag(vid.id(), args[flag]);
}
if (doFlags) {
flags(pid);
}
else if (doSysprops) {
sysprops(pid);
flags(vid.id());
}
if (doSysprops) {
sysprops(vid.id());
}
}
}

View File

@ -32,6 +32,7 @@ import java.io.UnsupportedEncodingException;
import java.util.Collection;
import com.sun.tools.attach.VirtualMachine;
import com.sun.tools.attach.VirtualMachineDescriptor;
import com.sun.tools.attach.AttachNotSupportedException;
import sun.tools.attach.HotSpotVirtualMachine;
import sun.tools.common.ProcessArgumentMatcher;
@ -89,10 +90,17 @@ public class JMap {
// Here we handle the built-in options
// As more options are added we should create an abstract tool class and
// have a table to map the options
ProcessArgumentMatcher ap = new ProcessArgumentMatcher(pidArg, JMap.class);
Collection<String> pids = ap.getPids();
for (String pid : pids) {
if (pids.size() > 1) {
ProcessArgumentMatcher ap = new ProcessArgumentMatcher(pidArg);
Collection<VirtualMachineDescriptor> vids = ap.getVirtualMachineDescriptors(JMap.class);
if (vids.isEmpty()) {
System.err.println("Could not find any processes matching : '" + pidArg + "'");
System.exit(1);
}
for (VirtualMachineDescriptor vid : vids) {
String pid = vid.id();
if (vids.size() > 1) {
System.out.println("Pid:" + pid);
}
if (option.equals("-histo")) {

View File

@ -29,6 +29,7 @@ import java.io.InputStream;
import java.util.Collection;
import com.sun.tools.attach.VirtualMachine;
import com.sun.tools.attach.VirtualMachineDescriptor;
import sun.tools.attach.HotSpotVirtualMachine;
import sun.tools.common.ProcessArgumentMatcher;
@ -82,13 +83,19 @@ public class JStack {
} else {
params = new String[0];
}
ProcessArgumentMatcher ap = new ProcessArgumentMatcher(pidArg, JStack.class);
Collection<String> pids = ap.getPids();
for (String pid : pids) {
if (pids.size() > 1) {
System.out.println("Pid:" + pid);
ProcessArgumentMatcher ap = new ProcessArgumentMatcher(pidArg);
Collection<VirtualMachineDescriptor> vids = ap.getVirtualMachineDescriptors(JStack.class);
if (vids.isEmpty()) {
System.err.println("Could not find any processes matching : '" + pidArg + "'");
System.exit(1);
}
runThreadDump(pid, params);
for (VirtualMachineDescriptor vid : vids) {
if (vids.size() > 1) {
System.out.println("Pid:" + vid.id());
}
runThreadDump(vid.id(), params);
}
}

View File

@ -102,35 +102,42 @@ public class MonitoredVmUtil {
*/
public static String mainClass(MonitoredVm vm, boolean fullPath)
throws MonitorException {
String commandLine = commandLine(vm);
String arg0 = commandLine;
int firstSpace = commandLine.indexOf(' ');
String cmdLine = commandLine(vm);
int firstSpace = cmdLine.indexOf(' ');
if (firstSpace > 0) {
arg0 = commandLine.substring(0, firstSpace);
cmdLine = cmdLine.substring(0, firstSpace);
}
if (fullPath) {
return cmdLine;
}
if (!fullPath) {
/*
* can't use File.separator() here because the separator
* for the target jvm may be different than the separator
* for the monitoring jvm.
* Can't use File.separator() here because the separator for the target
* jvm may be different than the separator for the monitoring jvm.
* And we also strip embedded module e.g. "module/MainClass"
*/
int lastFileSeparator = arg0.lastIndexOf('/');
if (lastFileSeparator > 0) {
return arg0.substring(lastFileSeparator + 1);
int lastSlash = cmdLine.lastIndexOf("/");
int lastBackslash = cmdLine.lastIndexOf("\\");
int lastSeparator = lastSlash > lastBackslash ? lastSlash : lastBackslash;
if (lastSeparator > 0) {
cmdLine = cmdLine.substring(lastSeparator + 1);
}
lastFileSeparator = arg0.lastIndexOf('\\');
if (lastFileSeparator > 0) {
return arg0.substring(lastFileSeparator + 1);
}
int lastPackageSeparator = arg0.lastIndexOf('.');
int lastPackageSeparator = cmdLine.lastIndexOf('.');
if (lastPackageSeparator > 0) {
return arg0.substring(lastPackageSeparator + 1);
String lastPart = cmdLine.substring(lastPackageSeparator + 1);
/*
* We could have a relative path "my.module" or
* a module called "my.module" and a jar file called "my.jar" or
* class named "jar" in package "my", e.g. "my.jar".
* We can never be sure here, but we assume *.jar is a jar file
*/
if (lastPart.equals("jar")) {
return cmdLine; /* presumably a file name without path */
}
return lastPart; /* presumably a class name without package */
}
return arg0;
return cmdLine;
}
/**

View File

@ -146,6 +146,16 @@ public class BasicLauncherTest {
launch(expectedMessage, Arrays.asList(toolArgs));
}
public static void launchNotOSX(String expectedMessage, String... toolArgs)
throws IOException {
if (Platform.isOSX()) {
// Coredump stackwalking is not implemented for Darwin
System.out.println("This test is not expected to work on OS X. Skipping");
return;
}
}
public static void testHeapDump() throws IOException {
File dump = new File("jhsdb.jmap.dump." +
System.currentTimeMillis() + ".hprof");
@ -172,7 +182,7 @@ public class BasicLauncherTest {
launchCLHSDB();
launch("No deadlocks found", "jstack");
launchNotOSX("No deadlocks found", "jstack");
launch("compiler detected", "jmap");
launch("Java System Properties", "jinfo");
launch("java.threads", "jsnap");

View File

@ -0,0 +1,124 @@
/*
* Copyright (c) 2005, 2016, 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.
*/
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.io.IOException;
import jdk.test.lib.JDKToolLauncher;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
import jdk.test.lib.apps.LingeredApp;
/*
* @test
* @summary Unit test for jinfo utility
* @modules java.base/jdk.internal.misc
* @library /test/lib/share/classes
* @build jdk.test.lib.*
* @build jdk.test.lib.apps.*
* @build jdk.test.lib.process.*
* @run main JInfoTest
*/
public class JInfoTest {
private static ProcessBuilder processBuilder = new ProcessBuilder();
public static void main(String[] args) throws Exception {
classNameMatch();
setMultipleFlags();
setFlag();
}
private static void setFlag() throws Exception {
System.out.println("#### setFlag ####");
LingeredApp app1 = new JInfoTestLingeredApp();
LingeredApp app2 = new JInfoTestLingeredApp();
try {
ArrayList<String> params = new ArrayList<String>();
LingeredApp.startApp(params, app1);
LingeredApp.startApp(params, app2);
OutputAnalyzer output = jinfo("-flag", "MinHeapFreeRatio=1", "JInfoTestLingeredApp");
output.shouldHaveExitValue(0);
output = jinfo("-flag", "MinHeapFreeRatio", "JInfoTestLingeredApp");
output.shouldHaveExitValue(0);
documentMatch(output.getStdout(), ".*MinHeapFreeRatio=1.*MinHeapFreeRatio=1.*");
} finally {
JInfoTestLingeredApp.stopApp(app1);
JInfoTestLingeredApp.stopApp(app2);
}
}
private static void setMultipleFlags() throws Exception {
System.out.println("#### setMultipleFlags ####");
OutputAnalyzer output = jinfo("-sysprops", "-flag", "MinHeapFreeRatio=1", "-flags", "JInfoTestLingeredApp");
output.shouldHaveExitValue(1);
}
private static void classNameMatch() throws Exception {
System.out.println("#### classNameMatch ####");
LingeredApp app1 = new JInfoTestLingeredApp();
LingeredApp app2 = new JInfoTestLingeredApp();
try {
ArrayList<String> params = new ArrayList<String>();
LingeredApp.startApp(params, app1);
LingeredApp.startApp(params, app2);
OutputAnalyzer output = jinfo("JInfoTestLingeredApp");
output.shouldHaveExitValue(0);
// "HotSpot(TM)" written once per proc
documentMatch(output.getStdout(), ".*HotSpot\\(TM\\).*HotSpot\\(TM\\).*");
} finally {
JInfoTestLingeredApp.stopApp(app1);
JInfoTestLingeredApp.stopApp(app2);
}
}
private static void documentMatch(String data, String pattern){
Matcher matcher = Pattern.compile(pattern, Pattern.DOTALL).matcher(data);
if (!matcher.find()) {
throw new RuntimeException("'" + pattern + "' missing from stdout \n");
}
}
private static OutputAnalyzer jinfo(String... toolArgs) throws Exception {
JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jinfo");
if (toolArgs != null) {
for (String toolArg : toolArgs) {
launcher.addToolArg(toolArg);
}
}
processBuilder.command(launcher.getCommand());
OutputAnalyzer output = ProcessTools.executeProcess(processBuilder);
return output;
}
}
// Sometime there is LingeredApp's from other test still around
class JInfoTestLingeredApp extends LingeredApp {
}

View File

@ -23,15 +23,17 @@
import jdk.testlibrary.Asserts;
import jdk.testlibrary.OutputAnalyzer;
import jdk.test.lib.apps.LingeredApp;
/*
* @test
* @summary This test verifies jps usage and checks that appropriate error message is shown
* when running jps with illegal arguments.
* @library /lib/testlibrary
* @library /lib/testlibrary /test/lib/share/classes
* @modules jdk.jartool/sun.tools.jar
* java.management
* @build jdk.testlibrary.* JpsHelper
* java.base/jdk.internal.misc
* @build jdk.testlibrary.* jdk.test.lib.apps.* JpsHelper
* @run driver TestJpsSanity
*/
public class TestJpsSanity {
@ -40,6 +42,42 @@ public class TestJpsSanity {
testJpsUsage();
testJpsVersion();
testJpsUnknownHost();
testJpsShort();
testJpsLong();
testJpsShortPkg();
testJpsLongPkg();
}
private static void testJpsShort() throws Exception {
OutputAnalyzer output = JpsHelper.jps();
output.shouldMatch("^[0-9]+ Jps$");
}
private static void testJpsLong() throws Exception {
OutputAnalyzer output = JpsHelper.jps("-l");
output.shouldMatch("^[0-9]+ jdk\\.jcmd/sun\\.tools\\.jps\\.Jps$");
}
private static void testJpsShortPkg() throws Exception {
LingeredApp app = null;
try {
app = LingeredApp.startApp();
OutputAnalyzer output = JpsHelper.jps();
output.shouldMatch("^[0-9]+ LingeredApp$");
} finally {
LingeredApp.stopApp(app);
}
}
private static void testJpsLongPkg() throws Exception {
LingeredApp app = null;
try {
app = LingeredApp.startApp();
OutputAnalyzer output = JpsHelper.jps("-l");
output.shouldMatch("^[0-9]+ jdk\\.test\\.lib\\.apps\\.LingeredApp$");
} finally {
LingeredApp.stopApp(app);
}
}
private static void testJpsUsage() throws Exception {