# HG changeset patch # User rehn # Date 1462855960 -7200 # Node ID 8ea2d56bfdf39ab1d9ec2106f00fbc3cc608a49a # Parent fb63be22ffa62bbfe1e672df2f65fafc9371d0fb 8154985: Add the ability to use main class as lookup (as jcmd) to jinfo, jmap, jstack Reviewed-by: sla, dsamersoff diff -r fb63be22ffa6 -r 8ea2d56bfdf3 jdk/src/jdk.jcmd/share/classes/sun/tools/common/ProcessArgumentMatcher.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.jcmd/share/classes/sun/tools/common/ProcessArgumentMatcher.java Tue May 10 06:52:40 2016 +0200 @@ -0,0 +1,128 @@ +/* + * Copyright (c) 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package sun.tools.common; + +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import com.sun.tools.attach.VirtualMachine; +import com.sun.tools.attach.VirtualMachineDescriptor; + +import sun.jvmstat.monitor.MonitorException; +import sun.jvmstat.monitor.MonitoredHost; +import sun.jvmstat.monitor.MonitoredVm; +import sun.jvmstat.monitor.MonitoredVmUtil; +import sun.jvmstat.monitor.VmIdentifier; + +/** + * Class for finding process matching a process argument, + * excluding tool it self and returning a list containing + * the process identifiers. + */ +public class ProcessArgumentMatcher { + private String excludeCls; + private String matchClass = null; + private String singlePid = null; + private boolean matchAll = false; + + public ProcessArgumentMatcher(String pidArg, Class excludeClass) { + excludeCls = excludeClass.getName(); + if (pidArg == null || pidArg.isEmpty()) { + throw new IllegalArgumentException("Pid string is invalid"); + } + if (pidArg.charAt(0) == '-') { + throw new IllegalArgumentException("Unrecognized " + pidArg); + } + try { + long pid = Long.parseLong(pidArg); + if (pid == 0) { + matchAll = true; + } else { + singlePid = String.valueOf(pid); + } + } catch (NumberFormatException nfe) { + matchClass = pidArg; + } + } + + private boolean check(VirtualMachineDescriptor vmd) { + String mainClass = null; + try { + VmIdentifier vmId = new VmIdentifier(vmd.id()); + MonitoredHost monitoredHost = MonitoredHost.getMonitoredHost(vmId); + MonitoredVm monitoredVm = monitoredHost.getMonitoredVm(vmId, -1); + mainClass = MonitoredVmUtil.mainClass(monitoredVm, true); + monitoredHost.detach(monitoredVm); + } catch (NullPointerException npe) { + // There is a potential race, where a running java app is being + // queried, unfortunately the java app has shutdown after this + // method is started but before getMonitoredVM is called. + // If this is the case, then the /tmp/hsperfdata_xxx/pid file + // will have disappeared and we will get a NullPointerException. + // 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)) { + return false; + } + + if (matchAll || mainClass.indexOf(matchClass) != -1) { + return true; + } + + return false; + } + + public Collection getPids() { + Collection pids = new ArrayList<>(); + if (singlePid != null) { + pids.add(singlePid); + return pids; + } + List vmds = VirtualMachine.list(); + for (VirtualMachineDescriptor vmd : vmds) { + if (check(vmd)) { + pids.add(vmd.id()); + } + } + return pids; + } +} diff -r fb63be22ffa6 -r 8ea2d56bfdf3 jdk/src/jdk.jcmd/share/classes/sun/tools/jcmd/Arguments.java --- a/jdk/src/jdk.jcmd/share/classes/sun/tools/jcmd/Arguments.java Mon May 09 23:41:59 2016 +0300 +++ b/jdk/src/jdk.jcmd/share/classes/sun/tools/jcmd/Arguments.java Tue May 10 06:52:40 2016 +0200 @@ -33,16 +33,14 @@ private boolean listProcesses = false; private boolean listCounters = false; private boolean showUsage = false; - private int pid = -1; private String command = null; - private String processSubstring; + private String processString = null; public boolean isListProcesses() { return listProcesses; } public boolean isListCounters() { return listCounters; } public boolean isShowUsage() { return showUsage; } - public int getPid() { return pid; } public String getCommand() { return command; } - public String getProcessSubstring() { return processSubstring; } + public String getProcessString() { return processString; } public Arguments(String[] args) { if (args.length == 0 || args[0].equals("-l")) { @@ -55,15 +53,7 @@ return; } - try { - pid = Integer.parseInt(args[0]); - } catch (NumberFormatException ex) { - // use as a partial class-name instead - if (args[0].charAt(0) != '-') { - // unless it starts with a '-' - processSubstring = args[0]; - } - } + processString = args[0]; StringBuilder sb = new StringBuilder(); for (int i = 1; i < args.length; i++) { diff -r fb63be22ffa6 -r 8ea2d56bfdf3 jdk/src/jdk.jcmd/share/classes/sun/tools/jcmd/JCmd.java --- a/jdk/src/jdk.jcmd/share/classes/sun/tools/jcmd/JCmd.java Mon May 09 23:41:59 2016 +0300 +++ b/jdk/src/jdk.jcmd/share/classes/sun/tools/jcmd/JCmd.java Tue May 10 06:52:40 2016 +0200 @@ -29,22 +29,22 @@ import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.List; -import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.Comparator; import java.net.URISyntaxException; import com.sun.tools.attach.AttachOperationFailedException; import com.sun.tools.attach.VirtualMachine; import com.sun.tools.attach.VirtualMachineDescriptor; -import com.sun.tools.attach.AgentLoadException; import com.sun.tools.attach.AttachNotSupportedException; import sun.tools.attach.HotSpotVirtualMachine; +import sun.tools.common.ProcessArgumentMatcher; import sun.tools.jstat.JStatLogger; import sun.jvmstat.monitor.Monitor; import sun.jvmstat.monitor.MonitoredHost; import sun.jvmstat.monitor.MonitoredVm; -import sun.jvmstat.monitor.MonitoredVmUtil; import sun.jvmstat.monitor.MonitorException; import sun.jvmstat.monitor.VmIdentifier; @@ -73,52 +73,18 @@ System.exit(0); } - List pids = new ArrayList(); - if (arg.getPid() == 0) { - // find all VMs - List vmds = VirtualMachine.list(); - for (VirtualMachineDescriptor vmd : vmds) { - if (!isJCmdProcess(vmd)) { - pids.add(vmd.id()); - } - } - } else if (arg.getProcessSubstring() != null) { - // use the partial class-name match - List vmds = VirtualMachine.list(); - for (VirtualMachineDescriptor vmd : vmds) { - if (isJCmdProcess(vmd)) { - continue; - } - try { - String mainClass = getMainClass(vmd); - if (mainClass != null - && mainClass.indexOf(arg.getProcessSubstring()) != -1) { - pids.add(vmd.id()); - } - } 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(); - } - } - } - } - if (pids.isEmpty()) { - System.err.println("Could not find any processes matching : '" - + arg.getProcessSubstring() + "'"); - System.exit(1); - } - } else if (arg.getPid() == -1) { + Collection 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); - } else { - // Use the found pid - pids.add(arg.getPid() + ""); + } + if (pids.isEmpty()) { + System.err.println("Could not find any processes matching : '" + + arg.getProcessString() + "'"); + System.exit(1); } boolean success = true; @@ -199,36 +165,6 @@ } } - private static boolean isJCmdProcess(VirtualMachineDescriptor vmd) { - try { - String mainClass = getMainClass(vmd); - return mainClass != null && mainClass.equals(JCmd.class.getName()); - } catch (URISyntaxException|MonitorException ex) { - return false; - } - } - - private static String getMainClass(VirtualMachineDescriptor vmd) - throws URISyntaxException, MonitorException { - try { - String mainClass = null; - VmIdentifier vmId = new VmIdentifier(vmd.id()); - MonitoredHost monitoredHost = MonitoredHost.getMonitoredHost(vmId); - MonitoredVm monitoredVm = monitoredHost.getMonitoredVm(vmId, -1); - mainClass = MonitoredVmUtil.mainClass(monitoredVm, true); - monitoredHost.detach(monitoredVm); - return mainClass; - } catch(NullPointerException e) { - // There is a potential race, where a running java app is being - // queried, unfortunately the java app has shutdown after this - // method is started but before getMonitoredVM is called. - // If this is the case, then the /tmp/hsperfdata_xxx/pid file - // will have disappeared and we will get a NullPointerException. - // Handle this gracefully.... - return null; - } - } - /** * Class to compare two Monitor objects by name in ascending order. * (from jstat) diff -r fb63be22ffa6 -r 8ea2d56bfdf3 jdk/src/jdk.jcmd/share/classes/sun/tools/jinfo/JInfo.java --- a/jdk/src/jdk.jcmd/share/classes/sun/tools/jinfo/JInfo.java Mon May 09 23:41:59 2016 +0300 +++ b/jdk/src/jdk.jcmd/share/classes/sun/tools/jinfo/JInfo.java Tue May 10 06:52:40 2016 +0200 @@ -25,13 +25,14 @@ package sun.tools.jinfo; -import java.util.Arrays; import java.io.IOException; import java.io.InputStream; +import java.util.Collection; import com.sun.tools.attach.VirtualMachine; import sun.tools.attach.HotSpotVirtualMachine; +import sun.tools.common.ProcessArgumentMatcher; /* * This class is the main class for the JInfo utility. It parses its arguments @@ -82,28 +83,49 @@ // Next we check the parameter count. -flag allows extra parameters int paramCount = args.length - optionCount; - if ((doFlag && paramCount != 2) || (paramCount != 1)) { + if ((doFlag && paramCount != 2) || ((!doFlag && paramCount != 1))) { usage(1); } if (!doFlag && !doFlags && !doSysprops) { // Print flags and sysporps if no options given - sysprops(args[optionCount]); - System.out.println(); - flags(args[optionCount]); - System.out.println(); - commandLine(args[optionCount]); + ProcessArgumentMatcher ap = new ProcessArgumentMatcher(args[optionCount], JInfo.class); + Collection 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); + } } if (doFlag) { - flag(args[optionCount+1], args[optionCount]); + ProcessArgumentMatcher ap = new ProcessArgumentMatcher(args[optionCount+1], JInfo.class); + Collection pids = ap.getPids(); + for (String pid : pids) { + if (pids.size() > 1) { + System.out.println("Pid:" + pid); + } + flag(pid, args[optionCount]); + } } - else { - if (doFlags) { - flags(args[optionCount]); - } - else if (doSysprops) { - sysprops(args[optionCount]); + else if (doFlags || doSysprops) { + ProcessArgumentMatcher ap = new ProcessArgumentMatcher(args[optionCount], JInfo.class); + Collection pids = ap.getPids(); + for (String pid : pids) { + if (pids.size() > 1) { + System.out.println("Pid:" + pid); + } + if (doFlags) { + flags(pid); + } + else if (doSysprops) { + sysprops(pid); + } } } } @@ -193,24 +215,23 @@ private static void checkForUnsupportedOptions(String[] args) { // Check arguments for -F, and non-numeric value // and warn the user that SA is not supported anymore - + int maxCount = 1; int paramCount = 0; for (String s : args) { if (s.equals("-F")) { SAOptionError("-F option used"); } - + if (s.equals("-flag")) { + maxCount = 2; + } if (! s.startsWith("-")) { - if (! s.matches("[0-9]+")) { - SAOptionError("non PID argument"); - } paramCount += 1; } } - if (paramCount > 1) { - SAOptionError("More than one non-option argument"); + if (paramCount > maxCount) { + SAOptionError("More than " + maxCount + " non-option argument"); } } diff -r fb63be22ffa6 -r 8ea2d56bfdf3 jdk/src/jdk.jcmd/share/classes/sun/tools/jmap/JMap.java --- a/jdk/src/jdk.jcmd/share/classes/sun/tools/jmap/JMap.java Mon May 09 23:41:59 2016 +0300 +++ b/jdk/src/jdk.jcmd/share/classes/sun/tools/jmap/JMap.java Tue May 10 06:52:40 2016 +0200 @@ -29,10 +29,12 @@ import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; +import java.util.Collection; import com.sun.tools.attach.VirtualMachine; import com.sun.tools.attach.AttachNotSupportedException; import sun.tools.attach.HotSpotVirtualMachine; +import sun.tools.common.ProcessArgumentMatcher; /* * This class is the main class for the JMap utility. It parses its arguments @@ -83,22 +85,29 @@ usage(1); } - String pid = args[1]; + String pidArg = args[1]; // 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 - if (option.equals("-histo")) { - histo(pid, ""); - } else if (option.startsWith("-histo:")) { - histo(pid, option.substring("-histo:".length())); - } else if (option.startsWith("-dump:")) { - dump(pid, option.substring("-dump:".length())); - } else if (option.equals("-finalizerinfo")) { - executeCommandForPid(pid, "jcmd", "GC.finalizer_info"); - } else if (option.equals("-clstats")) { - executeCommandForPid(pid, "jcmd", "GC.class_stats"); - } else { - usage(1); + ProcessArgumentMatcher ap = new ProcessArgumentMatcher(pidArg, JMap.class); + Collection pids = ap.getPids(); + for (String pid : pids) { + if (pids.size() > 1) { + System.out.println("Pid:" + pid); + } + if (option.equals("-histo")) { + histo(pid, ""); + } else if (option.startsWith("-histo:")) { + histo(pid, option.substring("-histo:".length())); + } else if (option.startsWith("-dump:")) { + dump(pid, option.substring("-dump:".length())); + } else if (option.equals("-finalizerinfo")) { + executeCommandForPid(pid, "jcmd", "GC.finalizer_info"); + } else if (option.equals("-clstats")) { + executeCommandForPid(pid, "jcmd", "GC.class_stats"); + } else { + usage(1); + } } } @@ -204,9 +213,6 @@ */ if (! s.startsWith("-")) { - if (! s.matches("[0-9]+")) { - SAOptionError("non PID argument"); - } paramCount += 1; } } diff -r fb63be22ffa6 -r 8ea2d56bfdf3 jdk/src/jdk.jcmd/share/classes/sun/tools/jstack/JStack.java --- a/jdk/src/jdk.jcmd/share/classes/sun/tools/jstack/JStack.java Mon May 09 23:41:59 2016 +0300 +++ b/jdk/src/jdk.jcmd/share/classes/sun/tools/jstack/JStack.java Tue May 10 06:52:40 2016 +0200 @@ -26,10 +26,11 @@ package sun.tools.jstack; import java.io.InputStream; +import java.util.Collection; import com.sun.tools.attach.VirtualMachine; -import com.sun.tools.attach.AttachNotSupportedException; import sun.tools.attach.HotSpotVirtualMachine; +import sun.tools.common.ProcessArgumentMatcher; /* * This class is the main class for the JStack utility. It parses its arguments @@ -74,14 +75,21 @@ } // pass -l to thread dump operation to get extra lock info - String pid = args[optionCount]; + String pidArg = args[optionCount]; String params[]; if (locks) { params = new String[] { "-l" }; } else { params = new String[0]; } - runThreadDump(pid, params); + ProcessArgumentMatcher ap = new ProcessArgumentMatcher(pidArg, JStack.class); + Collection pids = ap.getPids(); + for (String pid : pids) { + if (pids.size() > 1) { + System.out.println("Pid:" + pid); + } + runThreadDump(pid, params); + } } // Attach to pid and perform a thread dump @@ -133,9 +141,6 @@ } if (! s.startsWith("-")) { - if (! s.matches("[0-9]+")) { - SAOptionError("non PID argument"); - } paramCount += 1; } }