Wed, 14 Dec 2011 20:06:21 -0500
Merge
1.1 --- a/src/share/vm/services/attachListener.cpp Fri Dec 09 19:28:34 2011 -0800 1.2 +++ b/src/share/vm/services/attachListener.cpp Wed Dec 14 20:06:21 2011 -0500 1.3 @@ -34,6 +34,7 @@ 1.4 #include "runtime/javaCalls.hpp" 1.5 #include "runtime/os.hpp" 1.6 #include "services/attachListener.hpp" 1.7 +#include "services/diagnosticCommand.hpp" 1.8 #include "services/heapDumper.hpp" 1.9 1.10 volatile bool AttachListener::_initialized; 1.11 @@ -148,6 +149,24 @@ 1.12 return JNI_OK; 1.13 } 1.14 1.15 +// A jcmd attach operation request was received, which will now 1.16 +// dispatch to the diagnostic commands used for serviceability functions. 1.17 +static jint jcmd(AttachOperation* op, outputStream* out) { 1.18 + Thread* THREAD = Thread::current(); 1.19 + // All the supplied jcmd arguments are stored as a single 1.20 + // string (op->arg(0)). This is parsed by the Dcmd framework. 1.21 + DCmd::parse_and_execute(out, op->arg(0), ' ', THREAD); 1.22 + if (HAS_PENDING_EXCEPTION) { 1.23 + java_lang_Throwable::print(PENDING_EXCEPTION, out); 1.24 + CLEAR_PENDING_EXCEPTION; 1.25 + // The exception has been printed on the output stream 1.26 + // If the JVM returns JNI_ERR, the attachAPI throws a generic I/O 1.27 + // exception and the content of the output stream is not processed. 1.28 + // By returning JNI_OK, the exception will be displayed on the client side 1.29 + } 1.30 + return JNI_OK; 1.31 +} 1.32 + 1.33 #ifndef SERVICES_KERNEL // Heap dumping not supported 1.34 // Implementation of "dumpheap" command. 1.35 // 1.36 @@ -366,6 +385,7 @@ 1.37 { "inspectheap", heap_inspection }, 1.38 { "setflag", set_flag }, 1.39 { "printflag", print_flag }, 1.40 + { "jcmd", jcmd }, 1.41 { NULL, NULL } 1.42 }; 1.43
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/src/share/vm/services/diagnosticArgument.cpp Wed Dec 14 20:06:21 2011 -0500 2.3 @@ -0,0 +1,112 @@ 2.4 +/* 2.5 + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. 2.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 2.7 + * 2.8 + * This code is free software; you can redistribute it and/or modify it 2.9 + * under the terms of the GNU General Public License version 2 only, as 2.10 + * published by the Free Software Foundation. 2.11 + * 2.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 2.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 2.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 2.15 + * version 2 for more details (a copy is included in the LICENSE file that 2.16 + * accompanied this code). 2.17 + * 2.18 + * You should have received a copy of the GNU General Public License version 2.19 + * 2 along with this work; if not, write to the Free Software Foundation, 2.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 2.21 + * 2.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2.23 + * or visit www.oracle.com if you need additional information or have any 2.24 + * questions. 2.25 + * 2.26 + */ 2.27 + 2.28 +#include "precompiled.hpp" 2.29 +#include "memory/allocation.inline.hpp" 2.30 +#include "runtime/thread.hpp" 2.31 +#include "services/diagnosticArgument.hpp" 2.32 + 2.33 +void GenDCmdArgument::read_value(const char* str, size_t len, TRAPS) { 2.34 + if (is_set()) { 2.35 + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), 2.36 + "Duplicates in diagnostic command arguments"); 2.37 + } 2.38 + parse_value(str, len, CHECK); 2.39 + set_is_set(true); 2.40 +} 2.41 + 2.42 +template <> void DCmdArgument<jlong>::parse_value(const char* str, 2.43 + size_t len, TRAPS) { 2.44 + if (sscanf(str, INT64_FORMAT, &_value) != 1) { 2.45 + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), 2.46 + "Integer parsing error in diagnostic command arguments"); 2.47 + } 2.48 +} 2.49 + 2.50 +template <> void DCmdArgument<jlong>::init_value(TRAPS) { 2.51 + if (has_default()) { 2.52 + this->parse_value(_default_string, strlen(_default_string), THREAD); 2.53 + if (HAS_PENDING_EXCEPTION) { 2.54 + fatal("Default string must be parsable"); 2.55 + } 2.56 + } else { 2.57 + set_value(0); 2.58 + } 2.59 +} 2.60 + 2.61 +template <> void DCmdArgument<jlong>::destroy_value() { } 2.62 + 2.63 +template <> void DCmdArgument<bool>::parse_value(const char* str, 2.64 + size_t len, TRAPS) { 2.65 + if (len == 0) { 2.66 + set_value(true); 2.67 + } else { 2.68 + if (strcasecmp(str, "true") == 0) { 2.69 + set_value(true); 2.70 + } else if (strcasecmp(str, "false") == 0) { 2.71 + set_value(false); 2.72 + } else { 2.73 + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), 2.74 + "Boolean parsing error in diagnostic command arguments"); 2.75 + } 2.76 + } 2.77 +} 2.78 + 2.79 +template <> void DCmdArgument<bool>::init_value(TRAPS) { 2.80 + if (has_default()) { 2.81 + this->parse_value(_default_string, strlen(_default_string), THREAD); 2.82 + if (HAS_PENDING_EXCEPTION) { 2.83 + fatal("Default string must be parsable"); 2.84 + } 2.85 + } else { 2.86 + set_value(false); 2.87 + } 2.88 +} 2.89 + 2.90 +template <> void DCmdArgument<bool>::destroy_value() { } 2.91 + 2.92 +template <> void DCmdArgument<char*>::parse_value(const char* str, 2.93 + size_t len, TRAPS) { 2.94 + _value = NEW_C_HEAP_ARRAY(char, len+1); 2.95 + strncpy(_value, str, len); 2.96 + _value[len] = 0; 2.97 +} 2.98 + 2.99 +template <> void DCmdArgument<char*>::init_value(TRAPS) { 2.100 + if (has_default()) { 2.101 + this->parse_value(_default_string, strlen(_default_string), THREAD); 2.102 + if (HAS_PENDING_EXCEPTION) { 2.103 + fatal("Default string must be parsable"); 2.104 + } 2.105 + } else { 2.106 + set_value(NULL); 2.107 + } 2.108 +} 2.109 + 2.110 +template <> void DCmdArgument<char*>::destroy_value() { 2.111 + if (_value != NULL) { 2.112 + FREE_C_HEAP_ARRAY(char, _value); 2.113 + set_value(NULL); 2.114 + } 2.115 +}
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/src/share/vm/services/diagnosticArgument.hpp Wed Dec 14 20:06:21 2011 -0500 3.3 @@ -0,0 +1,102 @@ 3.4 +/* 3.5 + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. 3.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3.7 + * 3.8 + * This code is free software; you can redistribute it and/or modify it 3.9 + * under the terms of the GNU General Public License version 2 only, as 3.10 + * published by the Free Software Foundation. 3.11 + * 3.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 3.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 3.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 3.15 + * version 2 for more details (a copy is included in the LICENSE file that 3.16 + * accompanied this code). 3.17 + * 3.18 + * You should have received a copy of the GNU General Public License version 3.19 + * 2 along with this work; if not, write to the Free Software Foundation, 3.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 3.21 + * 3.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 3.23 + * or visit www.oracle.com if you need additional information or have any 3.24 + * questions. 3.25 + * 3.26 + */ 3.27 + 3.28 +#ifndef SHARE_VM_SERVICES_DIAGNOSTICARGUMENT_HPP 3.29 +#define SHARE_VM_SERVICES_DIAGNOSTICARGUMENT_HPP 3.30 + 3.31 +#include "classfile/vmSymbols.hpp" 3.32 +#include "memory/allocation.hpp" 3.33 +#include "runtime/os.hpp" 3.34 +#include "runtime/thread.hpp" 3.35 +#include "utilities/exceptions.hpp" 3.36 + 3.37 +class GenDCmdArgument : public ResourceObj { 3.38 +protected: 3.39 + GenDCmdArgument* _next; 3.40 + const char* _name; 3.41 + const char* _description; 3.42 + const char* _type; 3.43 + const char* _default_string; 3.44 + bool _is_set; 3.45 + bool _is_mandatory; 3.46 + GenDCmdArgument(const char* name, const char* description, const char* type, 3.47 + const char* default_string, bool mandatory) { 3.48 + _name = name; 3.49 + _description = description; 3.50 + _type = type; 3.51 + _default_string = default_string; 3.52 + _is_mandatory = mandatory; 3.53 + _is_set = false; 3.54 + }; 3.55 +public: 3.56 + const char* name() { return _name; } 3.57 + const char* description() { return _description; } 3.58 + const char* type() { return _type; } 3.59 + const char* default_string() { return _default_string; } 3.60 + bool is_set() { return _is_set; } 3.61 + void set_is_set(bool b) { _is_set = b; } 3.62 + bool is_mandatory() { return _is_mandatory; } 3.63 + bool has_value() { return _is_set || _default_string != NULL; } 3.64 + bool has_default() { return _default_string != NULL; } 3.65 + void read_value(const char* str, size_t len, TRAPS); 3.66 + virtual void parse_value(const char* str, size_t len, TRAPS) = 0; 3.67 + virtual void init_value(TRAPS) = 0; 3.68 + virtual void reset(TRAPS) = 0; 3.69 + virtual void cleanup() = 0; 3.70 + void set_next(GenDCmdArgument* arg) { 3.71 + _next = arg; 3.72 + } 3.73 + GenDCmdArgument* next() { 3.74 + return _next; 3.75 + } 3.76 +}; 3.77 + 3.78 +template <class ArgType> class DCmdArgument: public GenDCmdArgument { 3.79 +private: 3.80 + ArgType _value; 3.81 +public: 3.82 + DCmdArgument(const char* name, const char* description, const char* type, 3.83 + bool mandatory) : 3.84 + GenDCmdArgument(name, description, type, NULL, mandatory) { } 3.85 + DCmdArgument(const char* name, const char* description, const char* type, 3.86 + bool mandatory, const char* defaultvalue) : 3.87 + GenDCmdArgument(name, description, type, defaultvalue, mandatory) 3.88 + { } 3.89 + ~DCmdArgument() { destroy_value(); } 3.90 + ArgType value() { return _value;} 3.91 + void set_value(ArgType v) { _value = v; } 3.92 + void reset(TRAPS) { 3.93 + destroy_value(); 3.94 + init_value(CHECK); 3.95 + _is_set = false; 3.96 + } 3.97 + void cleanup() { 3.98 + destroy_value(); 3.99 + } 3.100 + void parse_value(const char* str, size_t len, TRAPS); 3.101 + void init_value(TRAPS); 3.102 + void destroy_value(); 3.103 +}; 3.104 + 3.105 +#endif /* SHARE_VM_SERVICES_DIAGNOSTICARGUMENT_HPP */
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/src/share/vm/services/diagnosticCommand.cpp Wed Dec 14 20:06:21 2011 -0500 4.3 @@ -0,0 +1,131 @@ 4.4 +/* 4.5 + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. 4.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4.7 + * 4.8 + * This code is free software; you can redistribute it and/or modify it 4.9 + * under the terms of the GNU General Public License version 2 only, as 4.10 + * published by the Free Software Foundation. 4.11 + * 4.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 4.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 4.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 4.15 + * version 2 for more details (a copy is included in the LICENSE file that 4.16 + * accompanied this code). 4.17 + * 4.18 + * You should have received a copy of the GNU General Public License version 4.19 + * 2 along with this work; if not, write to the Free Software Foundation, 4.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 4.21 + * 4.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 4.23 + * or visit www.oracle.com if you need additional information or have any 4.24 + * questions. 4.25 + * 4.26 + */ 4.27 + 4.28 +#include "precompiled.hpp" 4.29 +#include "services/diagnosticArgument.hpp" 4.30 +#include "services/diagnosticCommand.hpp" 4.31 +#include "services/diagnosticFramework.hpp" 4.32 + 4.33 +HelpDCmd::HelpDCmd(outputStream* output, bool heap) : DCmd(output, heap), 4.34 + _all("-all", "Show help for all commands", "BOOLEAN", false, "false"), 4.35 + _cmd("command name", "The name of the command for which we want help", 4.36 + "STRING", false) { 4.37 + _dcmdparser.add_dcmd_option(&_all); 4.38 + _dcmdparser.add_dcmd_argument(&_cmd); 4.39 +}; 4.40 + 4.41 +void HelpDCmd::parse(CmdLine* line, char delim, TRAPS) { 4.42 + _dcmdparser.parse(line, delim, CHECK); 4.43 +} 4.44 + 4.45 +void HelpDCmd::print_help(outputStream* out) { 4.46 + _dcmdparser.print_help(out, name()); 4.47 +} 4.48 + 4.49 +void HelpDCmd::execute(TRAPS) { 4.50 + if (_all.value()) { 4.51 + GrowableArray<const char*>* cmd_list = DCmdFactory::DCmd_list(); 4.52 + for (int i = 0; i < cmd_list->length(); i++) { 4.53 + DCmdFactory* factory = DCmdFactory::factory(cmd_list->at(i), 4.54 + strlen(cmd_list->at(i))); 4.55 + if (!factory->is_hidden()) { 4.56 + output()->print_cr("%s%s", factory->name(), 4.57 + factory->is_enabled() ? "" : " [disabled]"); 4.58 + output()->print_cr("\t%s", factory->description()); 4.59 + output()->cr(); 4.60 + } 4.61 + factory = factory->next(); 4.62 + } 4.63 + } else if (_cmd.has_value()) { 4.64 + DCmd* cmd = NULL; 4.65 + DCmdFactory* factory = DCmdFactory::factory(_cmd.value(), 4.66 + strlen(_cmd.value())); 4.67 + if (factory != NULL) { 4.68 + output()->print_cr("%s%s", factory->name(), 4.69 + factory->is_enabled() ? "" : " [disabled]"); 4.70 + output()->print_cr(factory->description()); 4.71 + output()->print_cr("\nImpact: %s", factory->impact()); 4.72 + cmd = factory->create_resource_instance(output()); 4.73 + if (cmd != NULL) { 4.74 + DCmdMark mark(cmd); 4.75 + cmd->print_help(output()); 4.76 + } 4.77 + } else { 4.78 + output()->print_cr("Help unavailable : '%s' : No such command", _cmd.value()); 4.79 + } 4.80 + } else { 4.81 + output()->print_cr("The following commands are available:"); 4.82 + GrowableArray<const char *>* cmd_list = DCmdFactory::DCmd_list(); 4.83 + for (int i = 0; i < cmd_list->length(); i++) { 4.84 + DCmdFactory* factory = DCmdFactory::factory(cmd_list->at(i), 4.85 + strlen(cmd_list->at(i))); 4.86 + if (!factory->is_hidden()) { 4.87 + output()->print_cr("%s%s", factory->name(), 4.88 + factory->is_enabled() ? "" : " [disabled]"); 4.89 + } 4.90 + factory = factory->_next; 4.91 + } 4.92 + output()->print_cr("\nFor more information about a specific command use 'help <command>'."); 4.93 + } 4.94 +} 4.95 + 4.96 +void HelpDCmd::reset(TRAPS) { 4.97 + _dcmdparser.reset(CHECK); 4.98 +} 4.99 + 4.100 +void HelpDCmd::cleanup() { 4.101 + _dcmdparser.cleanup(); 4.102 +} 4.103 + 4.104 +int HelpDCmd::num_arguments() { 4.105 + ResourceMark rm; 4.106 + HelpDCmd* dcmd = new HelpDCmd(NULL, false); 4.107 + if (dcmd != NULL) { 4.108 + DCmdMark mark(dcmd); 4.109 + return dcmd->_dcmdparser.num_arguments(); 4.110 + } else { 4.111 + return 0; 4.112 + } 4.113 +} 4.114 + 4.115 +GrowableArray<const char*>* HelpDCmd::argument_name_array() { 4.116 + return _dcmdparser.argument_name_array(); 4.117 +} 4.118 + 4.119 +GrowableArray<DCmdArgumentInfo*>* HelpDCmd::argument_info_array() { 4.120 + return _dcmdparser.argument_info_array(); 4.121 +} 4.122 + 4.123 +void VersionDCmd::execute(TRAPS) { 4.124 + output()->print_cr("%s version %s", Abstract_VM_Version::vm_name(), 4.125 + Abstract_VM_Version::vm_release()); 4.126 + JDK_Version jdk_version = JDK_Version::current(); 4.127 + if (jdk_version.update_version() > 0) { 4.128 + output()->print_cr("JDK %d.%d_%02d", jdk_version.major_version(), 4.129 + jdk_version.minor_version(), jdk_version.update_version()); 4.130 + } else { 4.131 + output()->print_cr("JDK %d.%d", jdk_version.major_version(), 4.132 + jdk_version.minor_version()); 4.133 + } 4.134 +}
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/src/share/vm/services/diagnosticCommand.hpp Wed Dec 14 20:06:21 2011 -0500 5.3 @@ -0,0 +1,76 @@ 5.4 +/* 5.5 + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. 5.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5.7 + * 5.8 + * This code is free software; you can redistribute it and/or modify it 5.9 + * under the terms of the GNU General Public License version 2 only, as 5.10 + * published by the Free Software Foundation. 5.11 + * 5.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 5.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 5.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 5.15 + * version 2 for more details (a copy is included in the LICENSE file that 5.16 + * accompanied this code). 5.17 + * 5.18 + * You should have received a copy of the GNU General Public License version 5.19 + * 2 along with this work; if not, write to the Free Software Foundation, 5.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 5.21 + * 5.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 5.23 + * or visit www.oracle.com if you need additional information or have any 5.24 + * questions. 5.25 + * 5.26 + */ 5.27 + 5.28 +#ifndef SHARE_VM_SERVICES_DIAGNOSTICCOMMAND_HPP 5.29 +#define SHARE_VM_SERVICES_DIAGNOSTICCOMMAND_HPP 5.30 + 5.31 +#include "runtime/arguments.hpp" 5.32 +#include "classfile/vmSymbols.hpp" 5.33 +#include "utilities/ostream.hpp" 5.34 +#include "runtime/vm_version.hpp" 5.35 +#include "runtime/vmThread.hpp" 5.36 +#include "runtime/os.hpp" 5.37 +#include "services/diagnosticArgument.hpp" 5.38 +#include "services/diagnosticCommand.hpp" 5.39 +#include "services/diagnosticFramework.hpp" 5.40 + 5.41 +class HelpDCmd : public DCmd { 5.42 +protected: 5.43 + DCmdParser _dcmdparser; 5.44 + DCmdArgument<bool> _all; 5.45 + DCmdArgument<char*> _cmd; 5.46 +public: 5.47 + HelpDCmd(outputStream* output, bool heap); 5.48 + static const char* name() { return "help"; } 5.49 + static const char* description() { 5.50 + return "For more information about a specific command use 'help <command>'. " 5.51 + "With no argument this will show a list of available commands. " 5.52 + "'help all' will show help for all commands."; 5.53 + } 5.54 + static const char* impact() { return "Low: "; } 5.55 + static int num_arguments(); 5.56 + virtual void parse(CmdLine* line, char delim, TRAPS); 5.57 + virtual void execute(TRAPS); 5.58 + virtual void reset(TRAPS); 5.59 + virtual void cleanup(); 5.60 + virtual void print_help(outputStream* out); 5.61 + virtual GrowableArray<const char*>* argument_name_array(); 5.62 + virtual GrowableArray<DCmdArgumentInfo*>* argument_info_array(); 5.63 +}; 5.64 + 5.65 +class VersionDCmd : public DCmd { 5.66 +public: 5.67 + VersionDCmd(outputStream* output, bool heap) : DCmd(output,heap) { } 5.68 + static const char* name() { return "VM.version"; } 5.69 + static const char* description() { 5.70 + return "Print JVM version information."; 5.71 + } 5.72 + static const char* impact() { return "Low: "; } 5.73 + static int num_arguments() { return 0; } 5.74 + virtual void parse(CmdLine* line, char delim, TRAPS) { } 5.75 + virtual void execute(TRAPS); 5.76 + virtual void print_help(outputStream* out) { } 5.77 +}; 5.78 + 5.79 +#endif // SHARE_VM_SERVICES_DIAGNOSTICCOMMAND_HPP
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/src/share/vm/services/diagnosticFramework.cpp Wed Dec 14 20:06:21 2011 -0500 6.3 @@ -0,0 +1,450 @@ 6.4 +/* 6.5 + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. 6.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6.7 + * 6.8 + * This code is free software; you can redistribute it and/or modify it 6.9 + * under the terms of the GNU General Public License version 2 only, as 6.10 + * published by the Free Software Foundation. 6.11 + * 6.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 6.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 6.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 6.15 + * version 2 for more details (a copy is included in the LICENSE file that 6.16 + * accompanied this code). 6.17 + * 6.18 + * You should have received a copy of the GNU General Public License version 6.19 + * 2 along with this work; if not, write to the Free Software Foundation, 6.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 6.21 + * 6.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 6.23 + * or visit www.oracle.com if you need additional information or have any 6.24 + * questions. 6.25 + * 6.26 + */ 6.27 + 6.28 +#include "precompiled.hpp" 6.29 +#include "memory/oopFactory.hpp" 6.30 +#include "runtime/javaCalls.hpp" 6.31 +#include "runtime/mutexLocker.hpp" 6.32 +#include "services/diagnosticArgument.hpp" 6.33 +#include "services/diagnosticFramework.hpp" 6.34 +#include "services/management.hpp" 6.35 + 6.36 +CmdLine::CmdLine(const char* line, size_t len, bool no_command_name) { 6.37 + assert(line != NULL, "Command line string should not be NULL"); 6.38 + const char* line_end; 6.39 + const char* cmd_end; 6.40 + 6.41 + _cmd = line; 6.42 + line_end = &line[len]; 6.43 + 6.44 + // Skip whitespace in the beginning of the line. 6.45 + while (_cmd < line_end && isspace((int) _cmd[0])) { 6.46 + _cmd++; 6.47 + } 6.48 + cmd_end = _cmd; 6.49 + 6.50 + if (no_command_name) { 6.51 + _cmd = NULL; 6.52 + _cmd_len = 0; 6.53 + } else { 6.54 + // Look for end of the command name 6.55 + while (cmd_end < line_end && !isspace((int) cmd_end[0])) { 6.56 + cmd_end++; 6.57 + } 6.58 + _cmd_len = cmd_end - _cmd; 6.59 + } 6.60 + _args = cmd_end; 6.61 + _args_len = line_end - _args; 6.62 +} 6.63 + 6.64 +bool DCmdArgIter::next(TRAPS) { 6.65 + if (_len == 0) return false; 6.66 + // skipping spaces 6.67 + while (_cursor < _len - 1 && isspace(_buffer[_cursor])) { 6.68 + _cursor++; 6.69 + } 6.70 + // handling end of command line 6.71 + if (_cursor >= _len - 1) { 6.72 + _cursor = _len - 1; 6.73 + _key_addr = &_buffer[_len - 1]; 6.74 + _key_len = 0; 6.75 + _value_addr = &_buffer[_len - 1]; 6.76 + _value_len = 0; 6.77 + return false; 6.78 + } 6.79 + // extracting first item, argument or option name 6.80 + _key_addr = &_buffer[_cursor]; 6.81 + while (_cursor <= _len - 1 && _buffer[_cursor] != '=' && _buffer[_cursor] != _delim) { 6.82 + // argument can be surrounded by single or double quotes 6.83 + if (_buffer[_cursor] == '\"' || _buffer[_cursor] == '\'') { 6.84 + _key_addr++; 6.85 + char quote = _buffer[_cursor]; 6.86 + while (_cursor < _len - 1) { 6.87 + _cursor++; 6.88 + if (_buffer[_cursor] == quote && _buffer[_cursor - 1] != '\\') { 6.89 + break; 6.90 + } 6.91 + } 6.92 + if (_buffer[_cursor] != quote) { 6.93 + THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), 6.94 + "Format error in diagnostic command arguments", false); 6.95 + } 6.96 + break; 6.97 + } 6.98 + _cursor++; 6.99 + } 6.100 + _key_len = &_buffer[_cursor] - _key_addr; 6.101 + // check if the argument has the <key>=<value> format 6.102 + if (_cursor <= _len -1 && _buffer[_cursor] == '=') { 6.103 + _cursor++; 6.104 + _value_addr = &_buffer[_cursor]; 6.105 + // extract the value 6.106 + while (_cursor <= _len - 1 && _buffer[_cursor] != _delim) { 6.107 + // value can be surrounded by simple or double quotes 6.108 + if (_buffer[_cursor] == '\"' || _buffer[_cursor] == '\'') { 6.109 + _value_addr++; 6.110 + char quote = _buffer[_cursor]; 6.111 + while (_cursor < _len - 1) { 6.112 + _cursor++; 6.113 + if (_buffer[_cursor] == quote && _buffer[_cursor - 1] != '\\') { 6.114 + break; 6.115 + } 6.116 + } 6.117 + if (_buffer[_cursor] != quote) { 6.118 + THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), 6.119 + "Format error in diagnostic command arguments", false); 6.120 + } 6.121 + break; 6.122 + } 6.123 + _cursor++; 6.124 + } 6.125 + _value_len = &_buffer[_cursor] - _value_addr; 6.126 + } else { 6.127 + _value_addr = NULL; 6.128 + _value_len = 0; 6.129 + } 6.130 + return _key_len != 0; 6.131 +} 6.132 + 6.133 +bool DCmdInfo::by_name(void* cmd_name, DCmdInfo* info) { 6.134 + if (info == NULL) return false; 6.135 + return strcmp((const char*)cmd_name, info->name()) == 0; 6.136 +} 6.137 + 6.138 +void DCmdParser::add_dcmd_option(GenDCmdArgument* arg) { 6.139 + assert(arg != NULL, "Sanity"); 6.140 + if (_options == NULL) { 6.141 + _options = arg; 6.142 + } else { 6.143 + GenDCmdArgument* o = _options; 6.144 + while (o->next() != NULL) { 6.145 + o = o->next(); 6.146 + } 6.147 + o->set_next(arg); 6.148 + } 6.149 + arg->set_next(NULL); 6.150 + Thread* THREAD = Thread::current(); 6.151 + arg->init_value(THREAD); 6.152 + if (HAS_PENDING_EXCEPTION) { 6.153 + fatal("Initialization must be successful"); 6.154 + } 6.155 +} 6.156 + 6.157 +void DCmdParser::add_dcmd_argument(GenDCmdArgument* arg) { 6.158 + assert(arg != NULL, "Sanity"); 6.159 + if (_arguments_list == NULL) { 6.160 + _arguments_list = arg; 6.161 + } else { 6.162 + GenDCmdArgument* a = _arguments_list; 6.163 + while (a->next() != NULL) { 6.164 + a = a->next(); 6.165 + } 6.166 + a->set_next(arg); 6.167 + } 6.168 + arg->set_next(NULL); 6.169 + Thread* THREAD = Thread::current(); 6.170 + arg->init_value(THREAD); 6.171 + if (HAS_PENDING_EXCEPTION) { 6.172 + fatal("Initialization must be successful"); 6.173 + } 6.174 +} 6.175 + 6.176 +void DCmdParser::parse(CmdLine* line, char delim, TRAPS) { 6.177 + GenDCmdArgument* next_argument = _arguments_list; 6.178 + DCmdArgIter iter(line->args_addr(), line->args_len(), delim); 6.179 + bool cont = iter.next(CHECK); 6.180 + while (cont) { 6.181 + GenDCmdArgument* arg = lookup_dcmd_option(iter.key_addr(), 6.182 + iter.key_length()); 6.183 + if (arg != NULL) { 6.184 + arg->read_value(iter.value_addr(), iter.value_length(), CHECK); 6.185 + } else { 6.186 + if (next_argument != NULL) { 6.187 + arg = next_argument; 6.188 + arg->read_value(iter.key_addr(), iter.key_length(), CHECK); 6.189 + next_argument = next_argument->next(); 6.190 + } else { 6.191 + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), 6.192 + "Unknown argument in diagnostic command"); 6.193 + } 6.194 + } 6.195 + cont = iter.next(CHECK); 6.196 + } 6.197 + check(CHECK); 6.198 +} 6.199 + 6.200 +GenDCmdArgument* DCmdParser::lookup_dcmd_option(const char* name, size_t len) { 6.201 + GenDCmdArgument* arg = _options; 6.202 + while (arg != NULL) { 6.203 + if (strlen(arg->name()) == len && 6.204 + strncmp(name, arg->name(), len) == 0) { 6.205 + return arg; 6.206 + } 6.207 + arg = arg->next(); 6.208 + } 6.209 + return NULL; 6.210 +} 6.211 + 6.212 +void DCmdParser::check(TRAPS) { 6.213 + GenDCmdArgument* arg = _arguments_list; 6.214 + while (arg != NULL) { 6.215 + if (arg->is_mandatory() && !arg->has_value()) { 6.216 + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), 6.217 + "Missing argument for diagnostic command"); 6.218 + } 6.219 + arg = arg->next(); 6.220 + } 6.221 + arg = _options; 6.222 + while (arg != NULL) { 6.223 + if (arg->is_mandatory() && !arg->has_value()) { 6.224 + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), 6.225 + "Missing option for diagnostic command"); 6.226 + } 6.227 + arg = arg->next(); 6.228 + } 6.229 +} 6.230 + 6.231 +void DCmdParser::print_help(outputStream* out, const char* cmd_name) { 6.232 + out->print("\nSyntax : %s %s", cmd_name, _options == NULL ? "" : "[options]"); 6.233 + GenDCmdArgument* arg = _arguments_list; 6.234 + while (arg != NULL) { 6.235 + if (arg->is_mandatory()) { 6.236 + out->print(" <%s>", arg->name()); 6.237 + } else { 6.238 + out->print(" [<%s>]", arg->name()); 6.239 + } 6.240 + arg = arg->next(); 6.241 + } 6.242 + out->print_cr(""); 6.243 + if (_arguments_list != NULL) { 6.244 + out->print_cr("\nArguments:"); 6.245 + arg = _arguments_list; 6.246 + while (arg != NULL) { 6.247 + out->print("\t%s : %s %s (%s, ", arg->name(), 6.248 + arg->is_mandatory() ? "" : "[optional]", 6.249 + arg->description(), arg->type()); 6.250 + if (arg->has_default()) { 6.251 + out->print(arg->default_string()); 6.252 + } else { 6.253 + out->print("no default value"); 6.254 + } 6.255 + out->print_cr(")"); 6.256 + arg = arg->next(); 6.257 + } 6.258 + } 6.259 + if (_options != NULL) { 6.260 + out->print_cr("\nOptions: (options must be specified using the <key> or <key>=<value> syntax)"); 6.261 + arg = _options; 6.262 + while (arg != NULL) { 6.263 + out->print("\t%s : %s %s (%s, ", arg->name(), 6.264 + arg->is_mandatory() ? "" : "[optional]", 6.265 + arg->description(), arg->type()); 6.266 + if (arg->has_default()) { 6.267 + out->print(arg->default_string()); 6.268 + } else { 6.269 + out->print("no default value"); 6.270 + } 6.271 + out->print_cr(")"); 6.272 + arg = arg->next(); 6.273 + } 6.274 + } 6.275 +} 6.276 + 6.277 +void DCmdParser::reset(TRAPS) { 6.278 + GenDCmdArgument* arg = _arguments_list; 6.279 + while (arg != NULL) { 6.280 + arg->reset(CHECK); 6.281 + arg = arg->next(); 6.282 + } 6.283 + arg = _options; 6.284 + while (arg != NULL) { 6.285 + arg->reset(CHECK); 6.286 + arg = arg->next(); 6.287 + } 6.288 +} 6.289 + 6.290 +void DCmdParser::cleanup() { 6.291 + GenDCmdArgument* arg = _arguments_list; 6.292 + while (arg != NULL) { 6.293 + arg->cleanup(); 6.294 + arg = arg->next(); 6.295 + } 6.296 + arg = _options; 6.297 + while (arg != NULL) { 6.298 + arg->cleanup(); 6.299 + arg = arg->next(); 6.300 + } 6.301 +} 6.302 + 6.303 +int DCmdParser::num_arguments() { 6.304 + GenDCmdArgument* arg = _arguments_list; 6.305 + int count = 0; 6.306 + while (arg != NULL) { 6.307 + count++; 6.308 + arg = arg->next(); 6.309 + } 6.310 + arg = _options; 6.311 + while (arg != NULL) { 6.312 + count++; 6.313 + arg = arg->next(); 6.314 + } 6.315 + return count; 6.316 +} 6.317 + 6.318 +GrowableArray<const char *>* DCmdParser::argument_name_array() { 6.319 + int count = num_arguments(); 6.320 + GrowableArray<const char *>* array = new GrowableArray<const char *>(count); 6.321 + GenDCmdArgument* arg = _arguments_list; 6.322 + while (arg != NULL) { 6.323 + array->append(arg->name()); 6.324 + arg = arg->next(); 6.325 + } 6.326 + arg = _options; 6.327 + while (arg != NULL) { 6.328 + array->append(arg->name()); 6.329 + arg = arg->next(); 6.330 + } 6.331 + return array; 6.332 +} 6.333 + 6.334 +GrowableArray<DCmdArgumentInfo*>* DCmdParser::argument_info_array() { 6.335 + int count = num_arguments(); 6.336 + GrowableArray<DCmdArgumentInfo*>* array = new GrowableArray<DCmdArgumentInfo *>(count); 6.337 + int idx = 0; 6.338 + GenDCmdArgument* arg = _arguments_list; 6.339 + while (arg != NULL) { 6.340 + array->append(new DCmdArgumentInfo(arg->name(), arg->description(), 6.341 + arg->type(), arg->default_string(), arg->is_mandatory(), 6.342 + false, idx)); 6.343 + idx++; 6.344 + arg = arg->next(); 6.345 + } 6.346 + arg = _options; 6.347 + while (arg != NULL) { 6.348 + array->append(new DCmdArgumentInfo(arg->name(), arg->description(), 6.349 + arg->type(), arg->default_string(), arg->is_mandatory(), 6.350 + true)); 6.351 + arg = arg->next(); 6.352 + } 6.353 + return array; 6.354 +} 6.355 + 6.356 +DCmdFactory* DCmdFactory::_DCmdFactoryList = NULL; 6.357 + 6.358 +void DCmd::parse_and_execute(outputStream* out, const char* cmdline, 6.359 + char delim, TRAPS) { 6.360 + 6.361 + if (cmdline == NULL) return; // Nothing to do! 6.362 + DCmdIter iter(cmdline, '\n'); 6.363 + 6.364 + while (iter.has_next()) { 6.365 + CmdLine line = iter.next(); 6.366 + if (line.is_stop()) { 6.367 + break; 6.368 + } 6.369 + if (line.is_executable()) { 6.370 + DCmd* command = DCmdFactory::create_local_DCmd(line, out, CHECK); 6.371 + assert(command != NULL, "command error must be handled before this line"); 6.372 + DCmdMark mark(command); 6.373 + command->parse(&line, delim, CHECK); 6.374 + command->execute(CHECK); 6.375 + } 6.376 + } 6.377 +} 6.378 + 6.379 +Mutex* DCmdFactory::_dcmdFactory_lock = new Mutex(Mutex::leaf, "DCmdFactory", true); 6.380 + 6.381 +DCmdFactory* DCmdFactory::factory(const char* name, size_t len) { 6.382 + MutexLockerEx ml(_dcmdFactory_lock, Mutex::_no_safepoint_check_flag); 6.383 + DCmdFactory* factory = _DCmdFactoryList; 6.384 + while (factory != NULL) { 6.385 + if (strlen(factory->name()) == len && 6.386 + strncmp(name, factory->name(), len) == 0) { 6.387 + return factory; 6.388 + } 6.389 + factory = factory->_next; 6.390 + } 6.391 + return NULL; 6.392 +} 6.393 + 6.394 +int DCmdFactory::register_DCmdFactory(DCmdFactory* factory) { 6.395 + MutexLockerEx ml(_dcmdFactory_lock, Mutex::_no_safepoint_check_flag); 6.396 + factory->_next = _DCmdFactoryList; 6.397 + _DCmdFactoryList = factory; 6.398 + return 0; // Actually, there's no checks for duplicates 6.399 +} 6.400 + 6.401 +DCmd* DCmdFactory::create_global_DCmd(CmdLine &line, outputStream* out, TRAPS) { 6.402 + DCmdFactory* f = factory(line.cmd_addr(), line.cmd_len()); 6.403 + if (f != NULL) { 6.404 + if (f->is_enabled()) { 6.405 + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), 6.406 + f->disabled_message()); 6.407 + } 6.408 + return f->create_Cheap_instance(out); 6.409 + } 6.410 + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), 6.411 + "Unknown diagnostic command"); 6.412 +} 6.413 + 6.414 +DCmd* DCmdFactory::create_local_DCmd(CmdLine &line, outputStream* out, TRAPS) { 6.415 + DCmdFactory* f = factory(line.cmd_addr(), line.cmd_len()); 6.416 + if (f != NULL) { 6.417 + if (!f->is_enabled()) { 6.418 + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), 6.419 + f->disabled_message()); 6.420 + } 6.421 + return f->create_resource_instance(out); 6.422 + } 6.423 + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), 6.424 + "Unknown diagnostic command"); 6.425 +} 6.426 + 6.427 +GrowableArray<const char*>* DCmdFactory::DCmd_list() { 6.428 + MutexLockerEx ml(_dcmdFactory_lock, Mutex::_no_safepoint_check_flag); 6.429 + GrowableArray<const char*>* array = new GrowableArray<const char*>(); 6.430 + DCmdFactory* factory = _DCmdFactoryList; 6.431 + while (factory != NULL) { 6.432 + if (!factory->is_hidden()) { 6.433 + array->append(factory->name()); 6.434 + } 6.435 + factory = factory->next(); 6.436 + } 6.437 + return array; 6.438 +} 6.439 + 6.440 +GrowableArray<DCmdInfo*>* DCmdFactory::DCmdInfo_list() { 6.441 + MutexLockerEx ml(_dcmdFactory_lock, Mutex::_no_safepoint_check_flag); 6.442 + GrowableArray<DCmdInfo*>* array = new GrowableArray<DCmdInfo*>(); 6.443 + DCmdFactory* factory = _DCmdFactoryList; 6.444 + while (factory != NULL) { 6.445 + if (!factory->is_hidden()) { 6.446 + array->append(new DCmdInfo(factory->name(), 6.447 + factory->description(), factory->impact(), 6.448 + factory->num_arguments(), factory->is_enabled())); 6.449 + } 6.450 + factory = factory->next(); 6.451 + } 6.452 + return array; 6.453 +}
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/src/share/vm/services/diagnosticFramework.hpp Wed Dec 14 20:06:21 2011 -0500 7.3 @@ -0,0 +1,362 @@ 7.4 +/* 7.5 + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. 7.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 7.7 + * 7.8 + * This code is free software; you can redistribute it and/or modify it 7.9 + * under the terms of the GNU General Public License version 2 only, as 7.10 + * published by the Free Software Foundation. 7.11 + * 7.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 7.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 7.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 7.15 + * version 2 for more details (a copy is included in the LICENSE file that 7.16 + * accompanied this code). 7.17 + * 7.18 + * You should have received a copy of the GNU General Public License version 7.19 + * 2 along with this work; if not, write to the Free Software Foundation, 7.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 7.21 + * 7.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 7.23 + * or visit www.oracle.com if you need additional information or have any 7.24 + * questions. 7.25 + * 7.26 + */ 7.27 + 7.28 +#ifndef SHARE_VM_SERVICES_DIAGNOSTICFRAMEWORK_HPP 7.29 +#define SHARE_VM_SERVICES_DIAGNOSTICFRAMEWORK_HPP 7.30 + 7.31 +#include "classfile/vmSymbols.hpp" 7.32 +#include "memory/allocation.hpp" 7.33 +#include "runtime/arguments.hpp" 7.34 +#include "runtime/os.hpp" 7.35 +#include "runtime/vm_version.hpp" 7.36 +#include "runtime/vmThread.hpp" 7.37 +#include "utilities/ostream.hpp" 7.38 + 7.39 + 7.40 +// CmdLine is the class used to handle a command line containing a single 7.41 +// diagnostic command and its arguments. It provides methods to access the 7.42 +// command name and the beginning of the arguments. The class is also 7.43 +// able to identify commented command lines and the "stop" keyword 7.44 +class CmdLine : public StackObj { 7.45 +private: 7.46 + const char* _cmd; 7.47 + size_t _cmd_len; 7.48 + const char* _args; 7.49 + size_t _args_len; 7.50 +public: 7.51 + CmdLine(const char* line, size_t len, bool no_command_name); 7.52 + const char* args_addr() const { return _args; } 7.53 + size_t args_len() const { return _args_len; } 7.54 + const char* cmd_addr() const { return _cmd; } 7.55 + size_t cmd_len() const { return _cmd_len; } 7.56 + bool is_empty() { return _cmd_len == 0; } 7.57 + bool is_executable() { return is_empty() || _cmd[0] != '#'; } 7.58 + bool is_stop() { return !is_empty() && strncmp("stop", _cmd, _cmd_len) == 0; } 7.59 +}; 7.60 + 7.61 +// Iterator class taking a character string in input and returning a CmdLine 7.62 +// instance for each command line. The argument delimiter has to be specified. 7.63 +class DCmdIter : public StackObj { 7.64 + friend class DCmd; 7.65 +private: 7.66 + const char* _str; 7.67 + char _delim; 7.68 + size_t _len; 7.69 + size_t _cursor; 7.70 +public: 7.71 + 7.72 + DCmdIter(const char* str, char delim) { 7.73 + _str = str; 7.74 + _delim = delim; 7.75 + _len = strlen(str); 7.76 + _cursor = 0; 7.77 + } 7.78 + bool has_next() { return _cursor < _len; } 7.79 + CmdLine next() { 7.80 + assert(_cursor <= _len, "Cannot iterate more"); 7.81 + size_t n = _cursor; 7.82 + while (n < _len && _str[n] != _delim) n++; 7.83 + CmdLine line(&(_str[_cursor]), n - _cursor, false); 7.84 + _cursor = n + 1; 7.85 + // The default copy constructor of CmdLine is used to return a CmdLine 7.86 + // instance to the caller. 7.87 + return line; 7.88 + } 7.89 +}; 7.90 + 7.91 +// Iterator class to iterate over diagnostic command arguments 7.92 +class DCmdArgIter : public ResourceObj { 7.93 + const char* _buffer; 7.94 + size_t _len; 7.95 + size_t _cursor; 7.96 + const char* _key_addr; 7.97 + size_t _key_len; 7.98 + const char* _value_addr; 7.99 + size_t _value_len; 7.100 + char _delim; 7.101 +public: 7.102 + DCmdArgIter(const char* buf, size_t len, char delim) { 7.103 + _buffer = buf; 7.104 + _len = len; 7.105 + _delim = delim; 7.106 + _cursor = 0; 7.107 + } 7.108 + bool next(TRAPS); 7.109 + const char* key_addr() { return _key_addr; } 7.110 + size_t key_length() { return _key_len; } 7.111 + const char* value_addr() { return _value_addr; } 7.112 + size_t value_length() { return _value_len; } 7.113 +}; 7.114 + 7.115 +// A DCmdInfo instance provides a description of a diagnostic command. It is 7.116 +// used to export the description to the JMX interface of the framework. 7.117 +class DCmdInfo : public ResourceObj { 7.118 +protected: 7.119 + const char* _name; 7.120 + const char* _description; 7.121 + const char* _impact; 7.122 + int _num_arguments; 7.123 + bool _is_enabled; 7.124 +public: 7.125 + DCmdInfo(const char* name, 7.126 + const char* description, 7.127 + const char* impact, 7.128 + int num_arguments, 7.129 + bool enabled) { 7.130 + this->_name = name; 7.131 + this->_description = description; 7.132 + this->_impact = impact; 7.133 + this->_num_arguments = num_arguments; 7.134 + this->_is_enabled = enabled; 7.135 + } 7.136 + const char* name() const { return _name; } 7.137 + const char* description() const { return _description; } 7.138 + const char* impact() const { return _impact; } 7.139 + int num_arguments() const { return _num_arguments; } 7.140 + bool is_enabled() const { return _is_enabled; } 7.141 + 7.142 + static bool by_name(void* name, DCmdInfo* info); 7.143 +}; 7.144 + 7.145 +// A DCmdArgumentInfo instance provides a description of a diagnostic command 7.146 +// argument. It is used to export the description to the JMX interface of the 7.147 +// framework. 7.148 +class DCmdArgumentInfo : public ResourceObj { 7.149 +protected: 7.150 + const char* _name; 7.151 + const char* _description; 7.152 + const char* _type; 7.153 + const char* _default_string; 7.154 + bool _mandatory; 7.155 + bool _option; 7.156 + int _position; 7.157 +public: 7.158 + DCmdArgumentInfo(const char* name, const char* description, const char* type, 7.159 + const char* default_string, bool mandatory, bool option) { 7.160 + this->_name = name; 7.161 + this->_description = description; 7.162 + this->_type = type; 7.163 + this->_default_string = default_string; 7.164 + this->_option = option; 7.165 + this->_mandatory = mandatory; 7.166 + this->_option = option; 7.167 + this->_position = -1; 7.168 + } 7.169 + DCmdArgumentInfo(const char* name, const char* description, const char* type, 7.170 + const char* default_string, bool mandatory, bool option, 7.171 + int position) { 7.172 + this->_name = name; 7.173 + this->_description = description; 7.174 + this->_type = type; 7.175 + this->_default_string = default_string; 7.176 + this->_option = option; 7.177 + this->_mandatory = mandatory; 7.178 + this->_option = option; 7.179 + this->_position = position; 7.180 + } 7.181 + const char* name() const { return _name; } 7.182 + const char* description() const { return _description; } 7.183 + const char* type() const { return _type; } 7.184 + const char* default_string() const { return _default_string; } 7.185 + bool is_mandatory() const { return _mandatory; } 7.186 + bool is_option() const { return _option; } 7.187 + int position() const { return _position; } 7.188 +}; 7.189 + 7.190 +// The DCmdParser class can be used to create an argument parser for a 7.191 +// diagnostic command. It is not mandatory to use it to parse arguments. 7.192 +class DCmdParser { 7.193 +private: 7.194 + GenDCmdArgument* _options; 7.195 + GenDCmdArgument* _arguments_list; 7.196 + char _delim; 7.197 +public: 7.198 + DCmdParser() { 7.199 + _options = NULL; 7.200 + _arguments_list = NULL; 7.201 + } 7.202 + void add_dcmd_option(GenDCmdArgument* arg); 7.203 + void add_dcmd_argument(GenDCmdArgument* arg); 7.204 + GenDCmdArgument* lookup_dcmd_option(const char* name, size_t len); 7.205 + GenDCmdArgument* arguments_list() { return _arguments_list; }; 7.206 + void check(TRAPS); 7.207 + void parse(CmdLine* line, char delim, TRAPS); 7.208 + void print_help(outputStream* out, const char* cmd_name); 7.209 + void reset(TRAPS); 7.210 + void cleanup(); 7.211 + int num_arguments(); 7.212 + GrowableArray<const char*>* argument_name_array(); 7.213 + GrowableArray<DCmdArgumentInfo*>* argument_info_array(); 7.214 +}; 7.215 + 7.216 +// The DCmd class is the parent class of all diagnostic commands 7.217 +// Diagnostic command instances should not be instantiated directly but 7.218 +// created using the associated factory. The factory can be retrieved with 7.219 +// the DCmdFactory::getFactory() method. 7.220 +// A diagnostic command instance can either be allocated in the resource Area 7.221 +// or in the C-heap. Allocation in the resource area is recommended when the 7.222 +// current thread is the only one which will access the diagnostic command 7.223 +// instance. Allocation in the C-heap is required when the diagnostic command 7.224 +// is accessed by several threads (for instance to perform asynchronous 7.225 +// execution). 7.226 +// To ensure a proper cleanup, it's highly recommended to use a DCmdMark for 7.227 +// each diagnostic command instance. In case of a C-heap allocated diagnostic 7.228 +// command instance, the DCmdMark must be created in the context of the last 7.229 +// thread that will access the instance. 7.230 +class DCmd : public ResourceObj { 7.231 +protected: 7.232 + outputStream* _output; 7.233 + bool _is_heap_allocated; 7.234 +public: 7.235 + DCmd(outputStream* output, bool heap_allocated) { 7.236 + _output = output; 7.237 + _is_heap_allocated = heap_allocated; 7.238 + } 7.239 + 7.240 + static const char* name() { return "No Name";} 7.241 + static const char* description() { return "No Help";} 7.242 + static const char* disabled_message() { return "Diagnostic command currently disabled"; } 7.243 + static const char* impact() { return "Low: No impact"; } 7.244 + static int num_arguments() { return 0; } 7.245 + outputStream* output() { return _output; } 7.246 + bool is_heap_allocated() { return _is_heap_allocated; } 7.247 + virtual void print_help(outputStream* out) { }; 7.248 + virtual void parse(CmdLine* line, char delim, TRAPS) { } 7.249 + virtual void execute(TRAPS) { } 7.250 + virtual void reset(TRAPS) { } 7.251 + virtual void cleanup() { } 7.252 + 7.253 + // support for the JMX interface 7.254 + virtual GrowableArray<const char*>* argument_name_array() { 7.255 + GrowableArray<const char*>* array = new GrowableArray<const char*>(0); 7.256 + return array; 7.257 + } 7.258 + virtual GrowableArray<DCmdArgumentInfo*>* argument_info_array() { 7.259 + GrowableArray<DCmdArgumentInfo*>* array = new GrowableArray<DCmdArgumentInfo*>(0); 7.260 + return array; 7.261 + } 7.262 + 7.263 + // main method to invoke the framework 7.264 + static void parse_and_execute(outputStream* out, const char* cmdline, 7.265 + char delim, TRAPS); 7.266 +}; 7.267 + 7.268 +class DCmdMark : public StackObj { 7.269 + DCmd* _ref; 7.270 +public: 7.271 + DCmdMark(DCmd* cmd) { _ref = cmd; } 7.272 + ~DCmdMark() { 7.273 + if (_ref != NULL) { 7.274 + _ref->cleanup(); 7.275 + if (_ref->is_heap_allocated()) { 7.276 + delete _ref; 7.277 + } 7.278 + } 7.279 + } 7.280 +}; 7.281 + 7.282 +// Diagnostic commands are not directly instantiated but created with a factory. 7.283 +// Each diagnostic command class has its own factory. The DCmdFactory class also 7.284 +// manages the status of the diagnostic command (hidden, enabled). A DCmdFactory 7.285 +// has to be registered to make the diagnostic command available (see 7.286 +// management.cpp) 7.287 +class DCmdFactory: public CHeapObj { 7.288 +private: 7.289 + static Mutex* _dcmdFactory_lock; 7.290 + // Pointer to the next factory in the singly-linked list of registered 7.291 + // diagnostic commands 7.292 + DCmdFactory* _next; 7.293 + // When disabled, a diagnostic command cannot be executed. Any attempt to 7.294 + // execute it will result in the printing of the disabled message without 7.295 + // instantiating the command. 7.296 + bool _enabled; 7.297 + // When hidden, a diagnostic command doesn't appear in the list of commands 7.298 + // provided by the 'help' command. 7.299 + bool _hidden; 7.300 + int _num_arguments; 7.301 + static DCmdFactory* _DCmdFactoryList; 7.302 +public: 7.303 + DCmdFactory(int num_arguments, bool enabled, bool hidden) { 7.304 + _next = NULL; 7.305 + _enabled = enabled; 7.306 + _hidden = hidden; 7.307 + _num_arguments = num_arguments; 7.308 + } 7.309 + bool is_enabled() const { return _enabled; } 7.310 + void set_enabled(bool b) { _enabled = b; } 7.311 + bool is_hidden() const { return _hidden; } 7.312 + void set_hidden(bool b) { _hidden = b; } 7.313 + int num_arguments() { return _num_arguments; } 7.314 + DCmdFactory* next() { return _next; } 7.315 + virtual DCmd* create_Cheap_instance(outputStream* output) = 0; 7.316 + virtual DCmd* create_resource_instance(outputStream* output) = 0; 7.317 + virtual const char* name() const = 0; 7.318 + virtual const char* description() const = 0; 7.319 + virtual const char* impact() const = 0; 7.320 + virtual const char* disabled_message() const = 0; 7.321 + // Register a DCmdFactory to make a diagnostic command available. 7.322 + // Once registered, a diagnostic command must not be unregistered. 7.323 + // To prevent a diagnostic command from being executed, just set the 7.324 + // enabled flag to false. 7.325 + static int register_DCmdFactory(DCmdFactory* factory); 7.326 + static DCmdFactory* factory(const char* cmd, size_t len); 7.327 + // Returns a C-heap allocated diagnostic command for the given command line 7.328 + static DCmd* create_global_DCmd(CmdLine &line, outputStream* out, TRAPS); 7.329 + // Returns a resourceArea allocated diagnostic command for the given command line 7.330 + static DCmd* create_local_DCmd(CmdLine &line, outputStream* out, TRAPS); 7.331 + static GrowableArray<const char*>* DCmd_list(); 7.332 + static GrowableArray<DCmdInfo*>* DCmdInfo_list(); 7.333 + 7.334 + friend class HelpDCmd; 7.335 +}; 7.336 + 7.337 +// Template to easily create DCmdFactory instances. See management.cpp 7.338 +// where this template is used to create and register factories. 7.339 +template <class DCmdClass> class DCmdFactoryImpl : public DCmdFactory { 7.340 +public: 7.341 + DCmdFactoryImpl(bool enabled, bool hidden) : 7.342 + DCmdFactory(DCmdClass::num_arguments(), enabled, hidden) { } 7.343 + // Returns a C-heap allocated instance 7.344 + virtual DCmd* create_Cheap_instance(outputStream* output) { 7.345 + return new (ResourceObj::C_HEAP) DCmdClass(output, true); 7.346 + } 7.347 + // Returns a resourceArea allocated instance 7.348 + virtual DCmd* create_resource_instance(outputStream* output) { 7.349 + return new DCmdClass(output, false); 7.350 + } 7.351 + virtual const char* name() const { 7.352 + return DCmdClass::name(); 7.353 + } 7.354 + virtual const char* description() const { 7.355 + return DCmdClass::description(); 7.356 + } 7.357 + virtual const char* impact() const { 7.358 + return DCmdClass::impact(); 7.359 + } 7.360 + virtual const char* disabled_message() const { 7.361 + return DCmdClass::disabled_message(); 7.362 + } 7.363 +}; 7.364 + 7.365 +#endif // SHARE_VM_SERVICES_DIAGNOSTICFRAMEWORK_HPP
8.1 --- a/src/share/vm/services/jmm.h Fri Dec 09 19:28:34 2011 -0800 8.2 +++ b/src/share/vm/services/jmm.h Wed Dec 14 20:06:21 2011 -0500 8.3 @@ -48,7 +48,8 @@ 8.4 JMM_VERSION_1_0 = 0x20010000, 8.5 JMM_VERSION_1_1 = 0x20010100, // JDK 6 8.6 JMM_VERSION_1_2 = 0x20010200, // JDK 7 8.7 - JMM_VERSION = 0x20010201 8.8 + JMM_VERSION_1_2_1 = 0x20010201, // JDK 7 GA 8.9 + JMM_VERSION = 0x20010202 8.10 }; 8.11 8.12 typedef struct { 8.13 @@ -188,6 +189,24 @@ 8.14 /* -1 indicates gc_ext_attribute_values is not big enough */ 8.15 } jmmGCStat; 8.16 8.17 +typedef struct { 8.18 + const char* name; 8.19 + const char* description; 8.20 + const char* impact; 8.21 + int num_arguments; 8.22 + jboolean enabled; 8.23 +} dcmdInfo; 8.24 + 8.25 +typedef struct { 8.26 + const char* name; 8.27 + const char* description; 8.28 + const char* type; 8.29 + const char* default_string; 8.30 + jboolean mandatory; 8.31 + jboolean option; 8.32 + int position; 8.33 +} dcmdArgInfo; 8.34 + 8.35 typedef struct jmmInterface_1_ { 8.36 void* reserved1; 8.37 void* reserved2; 8.38 @@ -296,6 +315,18 @@ 8.39 void (JNICALL *SetGCNotificationEnabled) (JNIEnv *env, 8.40 jobject mgr, 8.41 jboolean enabled); 8.42 + jobjectArray (JNICALL *GetDiagnosticCommands) (JNIEnv *env); 8.43 + void (JNICALL *GetDiagnosticCommandInfo) 8.44 + (JNIEnv *env, 8.45 + jobjectArray cmds, 8.46 + dcmdInfo *infoArray); 8.47 + void (JNICALL *GetDiagnosticCommandArgumentsInfo) 8.48 + (JNIEnv *env, 8.49 + jstring commandName, 8.50 + dcmdArgInfo *infoArray); 8.51 + jstring (JNICALL *ExecuteDiagnosticCommand) 8.52 + (JNIEnv *env, 8.53 + jstring command); 8.54 } JmmInterface; 8.55 8.56 #ifdef __cplusplus
9.1 --- a/src/share/vm/services/management.cpp Fri Dec 09 19:28:34 2011 -0800 9.2 +++ b/src/share/vm/services/management.cpp Wed Dec 14 20:06:21 2011 -0500 9.3 @@ -40,7 +40,10 @@ 9.4 #include "runtime/os.hpp" 9.5 #include "runtime/serviceThread.hpp" 9.6 #include "services/classLoadingService.hpp" 9.7 +#include "services/diagnosticCommand.hpp" 9.8 +#include "services/diagnosticFramework.hpp" 9.9 #include "services/heapDumper.hpp" 9.10 +#include "services/jmm.h" 9.11 #include "services/lowMemoryDetector.hpp" 9.12 #include "services/gcNotifier.hpp" 9.13 #include "services/management.hpp" 9.14 @@ -113,6 +116,9 @@ 9.15 _optional_support.isSynchronizerUsageSupported = 1; 9.16 #endif // SERVICES_KERNEL 9.17 _optional_support.isThreadAllocatedMemorySupported = 1; 9.18 + 9.19 + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<HelpDCmd>(true, false)); 9.20 + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<VersionDCmd>(true, false)); 9.21 } 9.22 9.23 void Management::initialize(TRAPS) { 9.24 @@ -2107,6 +2113,122 @@ 9.25 #endif // SERVICES_KERNEL 9.26 JVM_END 9.27 9.28 +JVM_ENTRY(jobjectArray, jmm_GetDiagnosticCommands(JNIEnv *env)) 9.29 + ResourceMark rm(THREAD); 9.30 + GrowableArray<const char *>* dcmd_list = DCmdFactory::DCmd_list(); 9.31 + objArrayOop cmd_array_oop = oopFactory::new_objArray(SystemDictionary::String_klass(), 9.32 + dcmd_list->length(), CHECK_NULL); 9.33 + objArrayHandle cmd_array(THREAD, cmd_array_oop); 9.34 + for (int i = 0; i < dcmd_list->length(); i++) { 9.35 + oop cmd_name = java_lang_String::create_oop_from_str(dcmd_list->at(i), CHECK_NULL); 9.36 + cmd_array->obj_at_put(i, cmd_name); 9.37 + } 9.38 + return (jobjectArray) JNIHandles::make_local(env, cmd_array()); 9.39 +JVM_END 9.40 + 9.41 +JVM_ENTRY(void, jmm_GetDiagnosticCommandInfo(JNIEnv *env, jobjectArray cmds, 9.42 + dcmdInfo* infoArray)) 9.43 + if (cmds == NULL || infoArray == NULL) { 9.44 + THROW(vmSymbols::java_lang_NullPointerException()); 9.45 + } 9.46 + 9.47 + ResourceMark rm(THREAD); 9.48 + 9.49 + objArrayOop ca = objArrayOop(JNIHandles::resolve_non_null(cmds)); 9.50 + objArrayHandle cmds_ah(THREAD, ca); 9.51 + 9.52 + // Make sure we have a String array 9.53 + klassOop element_klass = objArrayKlass::cast(cmds_ah->klass())->element_klass(); 9.54 + if (element_klass != SystemDictionary::String_klass()) { 9.55 + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), 9.56 + "Array element type is not String class"); 9.57 + } 9.58 + 9.59 + GrowableArray<DCmdInfo *>* info_list = DCmdFactory::DCmdInfo_list(); 9.60 + 9.61 + int num_cmds = cmds_ah->length(); 9.62 + for (int i = 0; i < num_cmds; i++) { 9.63 + oop cmd = cmds_ah->obj_at(i); 9.64 + if (cmd == NULL) { 9.65 + THROW_MSG(vmSymbols::java_lang_NullPointerException(), 9.66 + "Command name cannot be null."); 9.67 + } 9.68 + char* cmd_name = java_lang_String::as_utf8_string(cmd); 9.69 + if (cmd_name == NULL) { 9.70 + THROW_MSG(vmSymbols::java_lang_NullPointerException(), 9.71 + "Command name cannot be null."); 9.72 + } 9.73 + int pos = info_list->find((void*)cmd_name,DCmdInfo::by_name); 9.74 + if (pos == -1) { 9.75 + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), 9.76 + "Unknown diagnostic command"); 9.77 + } 9.78 + DCmdInfo* info = info_list->at(pos); 9.79 + infoArray[i].name = info->name(); 9.80 + infoArray[i].description = info->description(); 9.81 + infoArray[i].impact = info->impact(); 9.82 + infoArray[i].num_arguments = info->num_arguments(); 9.83 + infoArray[i].enabled = info->is_enabled(); 9.84 + } 9.85 +JVM_END 9.86 + 9.87 +JVM_ENTRY(void, jmm_GetDiagnosticCommandArgumentsInfo(JNIEnv *env, 9.88 + jstring command, dcmdArgInfo* infoArray)) 9.89 + ResourceMark rm(THREAD); 9.90 + oop cmd = JNIHandles::resolve_external_guard(command); 9.91 + if (cmd == NULL) { 9.92 + THROW_MSG(vmSymbols::java_lang_NullPointerException(), 9.93 + "Command line cannot be null."); 9.94 + } 9.95 + char* cmd_name = java_lang_String::as_utf8_string(cmd); 9.96 + if (cmd_name == NULL) { 9.97 + THROW_MSG(vmSymbols::java_lang_NullPointerException(), 9.98 + "Command line content cannot be null."); 9.99 + } 9.100 + DCmd* dcmd = NULL; 9.101 + DCmdFactory*factory = DCmdFactory::factory(cmd_name, strlen(cmd_name)); 9.102 + if (factory != NULL) { 9.103 + dcmd = factory->create_resource_instance(NULL); 9.104 + } 9.105 + if (dcmd == NULL) { 9.106 + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), 9.107 + "Unknown diagnostic command"); 9.108 + } 9.109 + DCmdMark mark(dcmd); 9.110 + GrowableArray<DCmdArgumentInfo*>* array = dcmd->argument_info_array(); 9.111 + if (array->length() == 0) { 9.112 + return; 9.113 + } 9.114 + for (int i = 0; i < array->length(); i++) { 9.115 + infoArray[i].name = array->at(i)->name(); 9.116 + infoArray[i].description = array->at(i)->description(); 9.117 + infoArray[i].type = array->at(i)->type(); 9.118 + infoArray[i].default_string = array->at(i)->default_string(); 9.119 + infoArray[i].mandatory = array->at(i)->is_mandatory(); 9.120 + infoArray[i].option = array->at(i)->is_option(); 9.121 + infoArray[i].position = array->at(i)->position(); 9.122 + } 9.123 + return; 9.124 +JVM_END 9.125 + 9.126 +JVM_ENTRY(jstring, jmm_ExecuteDiagnosticCommand(JNIEnv *env, jstring commandline)) 9.127 + ResourceMark rm(THREAD); 9.128 + oop cmd = JNIHandles::resolve_external_guard(commandline); 9.129 + if (cmd == NULL) { 9.130 + THROW_MSG_NULL(vmSymbols::java_lang_NullPointerException(), 9.131 + "Command line cannot be null."); 9.132 + } 9.133 + char* cmdline = java_lang_String::as_utf8_string(cmd); 9.134 + if (cmdline == NULL) { 9.135 + THROW_MSG_NULL(vmSymbols::java_lang_NullPointerException(), 9.136 + "Command line content cannot be null."); 9.137 + } 9.138 + bufferedStream output; 9.139 + DCmd::parse_and_execute(&output, cmdline, ' ', CHECK_NULL); 9.140 + oop result = java_lang_String::create_oop_from_str(output.as_string(), CHECK_NULL); 9.141 + return (jstring) JNIHandles::make_local(env, result); 9.142 +JVM_END 9.143 + 9.144 jlong Management::ticks_to_ms(jlong ticks) { 9.145 assert(os::elapsed_frequency() > 0, "Must be non-zero"); 9.146 return (jlong)(((double)ticks / (double)os::elapsed_frequency()) 9.147 @@ -2149,7 +2271,11 @@ 9.148 jmm_SetVMGlobal, 9.149 NULL, 9.150 jmm_DumpThreads, 9.151 - jmm_SetGCNotificationEnabled 9.152 + jmm_SetGCNotificationEnabled, 9.153 + jmm_GetDiagnosticCommands, 9.154 + jmm_GetDiagnosticCommandInfo, 9.155 + jmm_GetDiagnosticCommandArgumentsInfo, 9.156 + jmm_ExecuteDiagnosticCommand 9.157 }; 9.158 9.159 void* Management::get_jmm_interface(int version) {