src/share/vm/services/diagnosticFramework.hpp

Mon, 09 Jan 2012 10:27:24 +0100

author
fparain
date
Mon, 09 Jan 2012 10:27:24 +0100
changeset 3402
4f25538b54c9
parent 3329
3b688d6ff3d0
child 3478
a42c07c38c47
permissions
-rw-r--r--

7120511: Add diagnostic commands
Reviewed-by: acorn, phh, dcubed, sspitsyn

     1 /*
     2  * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.
     8  *
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    12  * version 2 for more details (a copy is included in the LICENSE file that
    13  * accompanied this code).
    14  *
    15  * You should have received a copy of the GNU General Public License version
    16  * 2 along with this work; if not, write to the Free Software Foundation,
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    18  *
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    20  * or visit www.oracle.com if you need additional information or have any
    21  * questions.
    22  *
    23  */
    25 #ifndef SHARE_VM_SERVICES_DIAGNOSTICFRAMEWORK_HPP
    26 #define SHARE_VM_SERVICES_DIAGNOSTICFRAMEWORK_HPP
    28 #include "classfile/vmSymbols.hpp"
    29 #include "memory/allocation.hpp"
    30 #include "runtime/arguments.hpp"
    31 #include "runtime/os.hpp"
    32 #include "runtime/vm_version.hpp"
    33 #include "runtime/vmThread.hpp"
    34 #include "utilities/ostream.hpp"
    37 // CmdLine is the class used to handle a command line containing a single
    38 // diagnostic command and its arguments. It provides methods to access the
    39 // command name and the beginning of the arguments. The class is also
    40 // able to identify commented command lines and the "stop" keyword
    41 class CmdLine : public StackObj {
    42 private:
    43   const char* _cmd;
    44   size_t      _cmd_len;
    45   const char* _args;
    46   size_t      _args_len;
    47 public:
    48   CmdLine(const char* line, size_t len, bool no_command_name);
    49   const char* args_addr() const { return _args; }
    50   size_t args_len() const { return _args_len; }
    51   const char* cmd_addr() const { return _cmd; }
    52   size_t cmd_len() const { return _cmd_len; }
    53   bool is_empty() { return _cmd_len == 0; }
    54   bool is_executable() { return is_empty() || _cmd[0] != '#'; }
    55   bool is_stop() { return !is_empty() && strncmp("stop", _cmd, _cmd_len) == 0; }
    56 };
    58 // Iterator class taking a character string in input and returning a CmdLine
    59 // instance for each command line. The argument delimiter has to be specified.
    60 class DCmdIter : public StackObj {
    61   friend class DCmd;
    62 private:
    63   const char* _str;
    64   char        _delim;
    65   size_t      _len;
    66   size_t      _cursor;
    67 public:
    69   DCmdIter(const char* str, char delim) {
    70     _str = str;
    71     _delim = delim;
    72     _len = strlen(str);
    73     _cursor = 0;
    74   }
    75   bool has_next() { return _cursor < _len; }
    76   CmdLine next() {
    77     assert(_cursor <= _len, "Cannot iterate more");
    78     size_t n = _cursor;
    79     while (n < _len && _str[n] != _delim) n++;
    80     CmdLine line(&(_str[_cursor]), n - _cursor, false);
    81     _cursor = n + 1;
    82     // The default copy constructor of CmdLine is used to return a CmdLine
    83     // instance to the caller.
    84     return line;
    85   }
    86 };
    88 // Iterator class to iterate over diagnostic command arguments
    89 class DCmdArgIter : public ResourceObj {
    90   const char* _buffer;
    91   size_t      _len;
    92   size_t      _cursor;
    93   const char* _key_addr;
    94   size_t      _key_len;
    95   const char* _value_addr;
    96   size_t      _value_len;
    97   char        _delim;
    98 public:
    99   DCmdArgIter(const char* buf, size_t len, char delim) {
   100     _buffer = buf;
   101     _len = len;
   102     _delim = delim;
   103     _cursor = 0;
   104   }
   105   bool next(TRAPS);
   106   const char* key_addr() { return _key_addr; }
   107   size_t key_length() { return _key_len; }
   108   const char* value_addr() { return _value_addr; }
   109   size_t value_length() { return _value_len; }
   110 };
   112 // A DCmdInfo instance provides a description of a diagnostic command. It is
   113 // used to export the description to the JMX interface of the framework.
   114 class DCmdInfo : public ResourceObj {
   115 protected:
   116   const char* _name;
   117   const char* _description;
   118   const char* _impact;
   119   int         _num_arguments;
   120   bool        _is_enabled;
   121 public:
   122   DCmdInfo(const char* name,
   123           const char* description,
   124           const char* impact,
   125           int num_arguments,
   126           bool enabled) {
   127     this->_name = name;
   128     this->_description = description;
   129     this->_impact = impact;
   130     this->_num_arguments = num_arguments;
   131     this->_is_enabled = enabled;
   132   }
   133   const char* name() const { return _name; }
   134   const char* description() const { return _description; }
   135   const char* impact() const { return _impact; }
   136   int num_arguments() const { return _num_arguments; }
   137   bool is_enabled() const { return _is_enabled; }
   139   static bool by_name(void* name, DCmdInfo* info);
   140 };
   142 // A DCmdArgumentInfo instance provides a description of a diagnostic command
   143 // argument. It is used to export the description to the JMX interface of the
   144 // framework.
   145 class DCmdArgumentInfo : public ResourceObj {
   146 protected:
   147   const char* _name;
   148   const char* _description;
   149   const char* _type;
   150   const char* _default_string;
   151   bool        _mandatory;
   152   bool        _option;
   153   int         _position;
   154 public:
   155   DCmdArgumentInfo(const char* name, const char* description, const char* type,
   156                    const char* default_string, bool mandatory, bool option) {
   157     this->_name = name;
   158     this->_description = description;
   159     this->_type = type;
   160     this->_default_string = default_string;
   161     this->_option = option;
   162     this->_mandatory = mandatory;
   163     this->_option = option;
   164     this->_position = -1;
   165   }
   166   DCmdArgumentInfo(const char* name, const char* description, const char* type,
   167                    const char* default_string, bool mandatory, bool option,
   168                    int position) {
   169     this->_name = name;
   170     this->_description = description;
   171     this->_type = type;
   172     this->_default_string = default_string;
   173     this->_option = option;
   174     this->_mandatory = mandatory;
   175     this->_option = option;
   176     this->_position = position;
   177   }
   178   const char* name() const { return _name; }
   179   const char* description() const { return _description; }
   180   const char* type() const { return _type; }
   181   const char* default_string() const { return _default_string; }
   182   bool is_mandatory() const { return _mandatory; }
   183   bool is_option() const { return _option; }
   184   int position() const { return _position; }
   185 };
   187 // The DCmdParser class can be used to create an argument parser for a
   188 // diagnostic command. It is not mandatory to use it to parse arguments.
   189 class DCmdParser {
   190 private:
   191   GenDCmdArgument* _options;
   192   GenDCmdArgument* _arguments_list;
   193   char             _delim;
   194 public:
   195   DCmdParser() {
   196     _options = NULL;
   197     _arguments_list = NULL;
   198   }
   199   void add_dcmd_option(GenDCmdArgument* arg);
   200   void add_dcmd_argument(GenDCmdArgument* arg);
   201   GenDCmdArgument* lookup_dcmd_option(const char* name, size_t len);
   202   GenDCmdArgument* arguments_list() { return _arguments_list; };
   203   void check(TRAPS);
   204   void parse(CmdLine* line, char delim, TRAPS);
   205   void print_help(outputStream* out, const char* cmd_name);
   206   void reset(TRAPS);
   207   void cleanup();
   208   int num_arguments();
   209   GrowableArray<const char*>* argument_name_array();
   210   GrowableArray<DCmdArgumentInfo*>* argument_info_array();
   211 };
   213 // The DCmd class is the parent class of all diagnostic commands
   214 // Diagnostic command instances should not be instantiated directly but
   215 // created using the associated factory. The factory can be retrieved with
   216 // the DCmdFactory::getFactory() method.
   217 // A diagnostic command instance can either be allocated in the resource Area
   218 // or in the C-heap. Allocation in the resource area is recommended when the
   219 // current thread is the only one which will access the diagnostic command
   220 // instance. Allocation in the C-heap is required when the diagnostic command
   221 // is accessed by several threads (for instance to perform asynchronous
   222 // execution).
   223 // To ensure a proper cleanup, it's highly recommended to use a DCmdMark for
   224 // each diagnostic command instance. In case of a C-heap allocated diagnostic
   225 // command instance, the DCmdMark must be created in the context of the last
   226 // thread that will access the instance.
   227 class DCmd : public ResourceObj {
   228 protected:
   229   outputStream* _output;
   230   bool          _is_heap_allocated;
   231 public:
   232   DCmd(outputStream* output, bool heap_allocated) {
   233     _output = output;
   234     _is_heap_allocated = heap_allocated;
   235   }
   237   static const char* name() { return "No Name";}
   238   static const char* description() { return "No Help";}
   239   static const char* disabled_message() { return "Diagnostic command currently disabled"; }
   240   static const char* impact() { return "Low: No impact"; }
   241   static int num_arguments() { return 0; }
   242   outputStream* output() { return _output; }
   243   bool is_heap_allocated()  { return _is_heap_allocated; }
   244   virtual void print_help(const char* name) {
   245     output()->print_cr("Syntax: %s", name);
   246   }
   247   virtual void parse(CmdLine* line, char delim, TRAPS) {
   248     DCmdArgIter iter(line->args_addr(), line->args_len(), delim);
   249     bool has_arg = iter.next(CHECK);
   250     if (has_arg) {
   251       THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
   252                 "Unknown argument in diagnostic command");
   253     }
   254   }
   255   virtual void execute(TRAPS) { }
   256   virtual void reset(TRAPS) { }
   257   virtual void cleanup() { }
   259   // support for the JMX interface
   260   virtual GrowableArray<const char*>* argument_name_array() {
   261     GrowableArray<const char*>* array = new GrowableArray<const char*>(0);
   262     return array;
   263   }
   264   virtual GrowableArray<DCmdArgumentInfo*>* argument_info_array() {
   265     GrowableArray<DCmdArgumentInfo*>* array = new GrowableArray<DCmdArgumentInfo*>(0);
   266     return array;
   267   }
   269   // main method to invoke the framework
   270   static void parse_and_execute(outputStream* out, const char* cmdline,
   271                                 char delim, TRAPS);
   272 };
   274 class DCmdWithParser : public DCmd {
   275 protected:
   276   DCmdParser _dcmdparser;
   277 public:
   278   DCmdWithParser (outputStream *output, bool heap=false) : DCmd(output, heap) { }
   279   static const char* name() { return "No Name";}
   280   static const char* description() { return "No Help";}
   281   static const char* disabled_message() { return "Diagnostic command currently disabled"; }
   282   static const char* impact() { return "Low: No impact"; }
   283   static int num_arguments() { return 0; }
   284   virtual void parse(CmdLine *line, char delim, TRAPS);
   285   virtual void execute(TRAPS) { }
   286   virtual void reset(TRAPS);
   287   virtual void cleanup();
   288   virtual void print_help(const char* name);
   289   virtual GrowableArray<const char*>* argument_name_array();
   290   virtual GrowableArray<DCmdArgumentInfo*>* argument_info_array();
   291 };
   293 class DCmdMark : public StackObj {
   294   DCmd* _ref;
   295 public:
   296   DCmdMark(DCmd* cmd) { _ref = cmd; }
   297   ~DCmdMark() {
   298     if (_ref != NULL) {
   299       _ref->cleanup();
   300       if (_ref->is_heap_allocated()) {
   301         delete _ref;
   302       }
   303     }
   304   }
   305 };
   307 // Diagnostic commands are not directly instantiated but created with a factory.
   308 // Each diagnostic command class has its own factory. The DCmdFactory class also
   309 // manages the status of the diagnostic command (hidden, enabled). A DCmdFactory
   310 // has to be registered to make the diagnostic command available (see
   311 // management.cpp)
   312 class DCmdFactory: public CHeapObj {
   313 private:
   314   static Mutex*       _dcmdFactory_lock;
   315   // Pointer to the next factory in the singly-linked list of registered
   316   // diagnostic commands
   317   DCmdFactory*        _next;
   318   // When disabled, a diagnostic command cannot be executed. Any attempt to
   319   // execute it will result in the printing of the disabled message without
   320   // instantiating the command.
   321   bool                _enabled;
   322   // When hidden, a diagnostic command doesn't appear in the list of commands
   323   // provided by the 'help' command.
   324   bool                _hidden;
   325   int                 _num_arguments;
   326   static DCmdFactory* _DCmdFactoryList;
   327 public:
   328   DCmdFactory(int num_arguments, bool enabled, bool hidden) {
   329     _next = NULL;
   330     _enabled = enabled;
   331     _hidden = hidden;
   332     _num_arguments = num_arguments;
   333   }
   334   bool is_enabled() const { return _enabled; }
   335   void set_enabled(bool b) { _enabled = b; }
   336   bool is_hidden() const { return _hidden; }
   337   void set_hidden(bool b) { _hidden = b; }
   338   int num_arguments() { return _num_arguments; }
   339   DCmdFactory* next() { return _next; }
   340   virtual DCmd* create_Cheap_instance(outputStream* output) = 0;
   341   virtual DCmd* create_resource_instance(outputStream* output) = 0;
   342   virtual const char* name() const = 0;
   343   virtual const char* description() const = 0;
   344   virtual const char* impact() const = 0;
   345   virtual const char* disabled_message() const = 0;
   346   // Register a DCmdFactory to make a diagnostic command available.
   347   // Once registered, a diagnostic command must not be unregistered.
   348   // To prevent a diagnostic command from being executed, just set the
   349   // enabled flag to false.
   350   static int register_DCmdFactory(DCmdFactory* factory);
   351   static DCmdFactory* factory(const char* cmd, size_t len);
   352   // Returns a C-heap allocated diagnostic command for the given command line
   353   static DCmd* create_global_DCmd(CmdLine &line, outputStream* out, TRAPS);
   354   // Returns a resourceArea allocated diagnostic command for the given command line
   355   static DCmd* create_local_DCmd(CmdLine &line, outputStream* out, TRAPS);
   356   static GrowableArray<const char*>* DCmd_list();
   357   static GrowableArray<DCmdInfo*>* DCmdInfo_list();
   359   friend class HelpDCmd;
   360 };
   362 // Template to easily create DCmdFactory instances. See management.cpp
   363 // where this template is used to create and register factories.
   364 template <class DCmdClass> class DCmdFactoryImpl : public DCmdFactory {
   365 public:
   366   DCmdFactoryImpl(bool enabled, bool hidden) :
   367     DCmdFactory(DCmdClass::num_arguments(), enabled, hidden) { }
   368   // Returns a C-heap allocated instance
   369   virtual DCmd* create_Cheap_instance(outputStream* output) {
   370     return new (ResourceObj::C_HEAP) DCmdClass(output, true);
   371   }
   372   // Returns a resourceArea allocated instance
   373   virtual DCmd* create_resource_instance(outputStream* output) {
   374     return new DCmdClass(output, false);
   375   }
   376   virtual const char* name() const {
   377     return DCmdClass::name();
   378   }
   379   virtual const char* description() const {
   380     return DCmdClass::description();
   381   }
   382   virtual const char* impact() const {
   383     return DCmdClass::impact();
   384   }
   385   virtual const char* disabled_message() const {
   386      return DCmdClass::disabled_message();
   387   }
   388 };
   390 #endif // SHARE_VM_SERVICES_DIAGNOSTICFRAMEWORK_HPP

mercurial