src/share/vm/services/attachListener.cpp

Fri, 25 Jan 2013 10:04:08 -0500

author
zgu
date
Fri, 25 Jan 2013 10:04:08 -0500
changeset 4492
8b46b0196eb0
parent 4193
716c64bda5ba
child 5047
31a4e55f8c9d
permissions
-rw-r--r--

8000692: Remove old KERNEL code
Summary: Removed depreciated kernel VM source code from hotspot VM
Reviewed-by: dholmes, acorn

     1 /*
     2  * Copyright (c) 2005, 2013, 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 #include "precompiled.hpp"
    26 #include "classfile/javaClasses.hpp"
    27 #include "classfile/systemDictionary.hpp"
    28 #include "gc_implementation/shared/vmGCOperations.hpp"
    29 #include "memory/resourceArea.hpp"
    30 #include "prims/jvmtiExport.hpp"
    31 #include "runtime/arguments.hpp"
    32 #include "runtime/globals.hpp"
    33 #include "runtime/java.hpp"
    34 #include "runtime/javaCalls.hpp"
    35 #include "runtime/os.hpp"
    36 #include "services/attachListener.hpp"
    37 #include "services/diagnosticCommand.hpp"
    38 #include "services/heapDumper.hpp"
    40 volatile bool AttachListener::_initialized;
    42 // Implementation of "properties" command.
    43 //
    44 // Invokes sun.misc.VMSupport.serializePropertiesToByteArray to serialize
    45 // the system properties into a byte array.
    47 static Klass* load_and_initialize_klass(Symbol* sh, TRAPS) {
    48   Klass* k = SystemDictionary::resolve_or_fail(sh, true, CHECK_NULL);
    49   instanceKlassHandle ik (THREAD, k);
    50   if (ik->should_be_initialized()) {
    51     ik->initialize(CHECK_NULL);
    52   }
    53   return ik();
    54 }
    56 static jint get_properties(AttachOperation* op, outputStream* out, Symbol* serializePropertiesMethod) {
    57   Thread* THREAD = Thread::current();
    58   HandleMark hm;
    60   // load sun.misc.VMSupport
    61   Symbol* klass = vmSymbols::sun_misc_VMSupport();
    62   Klass* k = load_and_initialize_klass(klass, THREAD);
    63   if (HAS_PENDING_EXCEPTION) {
    64     java_lang_Throwable::print(PENDING_EXCEPTION, out);
    65     CLEAR_PENDING_EXCEPTION;
    66     return JNI_ERR;
    67   }
    68   instanceKlassHandle ik(THREAD, k);
    70   // invoke the serializePropertiesToByteArray method
    71   JavaValue result(T_OBJECT);
    72   JavaCallArguments args;
    75   Symbol* signature = vmSymbols::serializePropertiesToByteArray_signature();
    76   JavaCalls::call_static(&result,
    77                            ik,
    78                            serializePropertiesMethod,
    79                            signature,
    80                            &args,
    81                            THREAD);
    82   if (HAS_PENDING_EXCEPTION) {
    83     java_lang_Throwable::print(PENDING_EXCEPTION, out);
    84     CLEAR_PENDING_EXCEPTION;
    85     return JNI_ERR;
    86   }
    88   // The result should be a [B
    89   oop res = (oop)result.get_jobject();
    90   assert(res->is_typeArray(), "just checking");
    91   assert(TypeArrayKlass::cast(res->klass())->element_type() == T_BYTE, "just checking");
    93   // copy the bytes to the output stream
    94   typeArrayOop ba = typeArrayOop(res);
    95   jbyte* addr = typeArrayOop(res)->byte_at_addr(0);
    96   out->print_raw((const char*)addr, ba->length());
    98   return JNI_OK;
    99 }
   101 // Implementation of "properties" command.
   102 // See also: PrintSystemPropertiesDCmd class
   103 static jint get_system_properties(AttachOperation* op, outputStream* out) {
   104   return get_properties(op, out, vmSymbols::serializePropertiesToByteArray_name());
   105 }
   107 // Implementation of "agent_properties" command.
   108 static jint get_agent_properties(AttachOperation* op, outputStream* out) {
   109   return get_properties(op, out, vmSymbols::serializeAgentPropertiesToByteArray_name());
   110 }
   112 // Implementation of "datadump" command.
   113 //
   114 // Raises a SIGBREAK signal so that VM dump threads, does deadlock detection,
   115 // etc. In theory this command should only post a DataDumpRequest to any
   116 // JVMTI environment that has enabled this event. However it's useful to
   117 // trigger the SIGBREAK handler.
   119 static jint data_dump(AttachOperation* op, outputStream* out) {
   120   if (!ReduceSignalUsage) {
   121     AttachListener::pd_data_dump();
   122   } else {
   123     if (JvmtiExport::should_post_data_dump()) {
   124       JvmtiExport::post_data_dump();
   125     }
   126   }
   127   return JNI_OK;
   128 }
   130 // Implementation of "threaddump" command - essentially a remote ctrl-break
   131 // See also: ThreadDumpDCmd class
   132 //
   133 static jint thread_dump(AttachOperation* op, outputStream* out) {
   134   bool print_concurrent_locks = false;
   135   if (op->arg(0) != NULL && strcmp(op->arg(0), "-l") == 0) {
   136     print_concurrent_locks = true;
   137   }
   139   // thread stacks
   140   VM_PrintThreads op1(out, print_concurrent_locks);
   141   VMThread::execute(&op1);
   143   // JNI global handles
   144   VM_PrintJNI op2(out);
   145   VMThread::execute(&op2);
   147   // Deadlock detection
   148   VM_FindDeadlocks op3(out);
   149   VMThread::execute(&op3);
   151   return JNI_OK;
   152 }
   154 // A jcmd attach operation request was received, which will now
   155 // dispatch to the diagnostic commands used for serviceability functions.
   156 static jint jcmd(AttachOperation* op, outputStream* out) {
   157   Thread* THREAD = Thread::current();
   158   // All the supplied jcmd arguments are stored as a single
   159   // string (op->arg(0)). This is parsed by the Dcmd framework.
   160   DCmd::parse_and_execute(out, op->arg(0), ' ', THREAD);
   161   if (HAS_PENDING_EXCEPTION) {
   162     java_lang_Throwable::print(PENDING_EXCEPTION, out);
   163     out->cr();
   164     CLEAR_PENDING_EXCEPTION;
   165     // The exception has been printed on the output stream
   166     // If the JVM returns JNI_ERR, the attachAPI throws a generic I/O
   167     // exception and the content of the output stream is not processed.
   168     // By returning JNI_OK, the exception will be displayed on the client side
   169   }
   170   return JNI_OK;
   171 }
   173 // Implementation of "dumpheap" command.
   174 // See also: HeapDumpDCmd class
   175 //
   176 // Input arguments :-
   177 //   arg0: Name of the dump file
   178 //   arg1: "-live" or "-all"
   179 jint dump_heap(AttachOperation* op, outputStream* out) {
   180   const char* path = op->arg(0);
   181   if (path == NULL || path[0] == '\0') {
   182     out->print_cr("No dump file specified");
   183   } else {
   184     bool live_objects_only = true;   // default is true to retain the behavior before this change is made
   185     const char* arg1 = op->arg(1);
   186     if (arg1 != NULL && (strlen(arg1) > 0)) {
   187       if (strcmp(arg1, "-all") != 0 && strcmp(arg1, "-live") != 0) {
   188         out->print_cr("Invalid argument to dumpheap operation: %s", arg1);
   189         return JNI_ERR;
   190       }
   191       live_objects_only = strcmp(arg1, "-live") == 0;
   192     }
   194     // Request a full GC before heap dump if live_objects_only = true
   195     // This helps reduces the amount of unreachable objects in the dump
   196     // and makes it easier to browse.
   197     HeapDumper dumper(live_objects_only /* request GC */);
   198     int res = dumper.dump(op->arg(0));
   199     if (res == 0) {
   200       out->print_cr("Heap dump file created");
   201     } else {
   202       // heap dump failed
   203       ResourceMark rm;
   204       char* error = dumper.error_as_C_string();
   205       if (error == NULL) {
   206         out->print_cr("Dump failed - reason unknown");
   207       } else {
   208         out->print_cr("%s", error);
   209       }
   210     }
   211   }
   212   return JNI_OK;
   213 }
   215 // Implementation of "inspectheap" command
   216 // See also: ClassHistogramDCmd class
   217 //
   218 // Input arguments :-
   219 //   arg0: "-live" or "-all"
   220 static jint heap_inspection(AttachOperation* op, outputStream* out) {
   221   bool live_objects_only = true;   // default is true to retain the behavior before this change is made
   222   const char* arg0 = op->arg(0);
   223   if (arg0 != NULL && (strlen(arg0) > 0)) {
   224     if (strcmp(arg0, "-all") != 0 && strcmp(arg0, "-live") != 0) {
   225       out->print_cr("Invalid argument to inspectheap operation: %s", arg0);
   226       return JNI_ERR;
   227     }
   228     live_objects_only = strcmp(arg0, "-live") == 0;
   229   }
   230   VM_GC_HeapInspection heapop(out, live_objects_only /* request full gc */, true /* need_prologue */);
   231   VMThread::execute(&heapop);
   232   return JNI_OK;
   233 }
   235 // set a boolean global flag using value from AttachOperation
   236 static jint set_bool_flag(const char* name, AttachOperation* op, outputStream* out) {
   237   bool value = true;
   238   const char* arg1;
   239   if ((arg1 = op->arg(1)) != NULL) {
   240     int tmp;
   241     int n = sscanf(arg1, "%d", &tmp);
   242     if (n != 1) {
   243       out->print_cr("flag value must be a boolean (1 or 0)");
   244       return JNI_ERR;
   245     }
   246     value = (tmp != 0);
   247   }
   248   bool res = CommandLineFlags::boolAtPut((char*)name, &value, ATTACH_ON_DEMAND);
   249   if (! res) {
   250     out->print_cr("setting flag %s failed", name);
   251   }
   252   return res? JNI_OK : JNI_ERR;
   253 }
   255 // set a intx global flag using value from AttachOperation
   256 static jint set_intx_flag(const char* name, AttachOperation* op, outputStream* out) {
   257   intx value;
   258   const char* arg1;
   259   if ((arg1 = op->arg(1)) != NULL) {
   260     int n = sscanf(arg1, INTX_FORMAT, &value);
   261     if (n != 1) {
   262       out->print_cr("flag value must be an integer");
   263       return JNI_ERR;
   264     }
   265   }
   266   bool res = CommandLineFlags::intxAtPut((char*)name, &value, ATTACH_ON_DEMAND);
   267   if (! res) {
   268     out->print_cr("setting flag %s failed", name);
   269   }
   271   return res? JNI_OK : JNI_ERR;
   272 }
   274 // set a uintx global flag using value from AttachOperation
   275 static jint set_uintx_flag(const char* name, AttachOperation* op, outputStream* out) {
   276   uintx value;
   277   const char* arg1;
   278   if ((arg1 = op->arg(1)) != NULL) {
   279     int n = sscanf(arg1, UINTX_FORMAT, &value);
   280     if (n != 1) {
   281       out->print_cr("flag value must be an unsigned integer");
   282       return JNI_ERR;
   283     }
   284   }
   285   bool res = CommandLineFlags::uintxAtPut((char*)name, &value, ATTACH_ON_DEMAND);
   286   if (! res) {
   287     out->print_cr("setting flag %s failed", name);
   288   }
   290   return res? JNI_OK : JNI_ERR;
   291 }
   293 // set a uint64_t global flag using value from AttachOperation
   294 static jint set_uint64_t_flag(const char* name, AttachOperation* op, outputStream* out) {
   295   uint64_t value;
   296   const char* arg1;
   297   if ((arg1 = op->arg(1)) != NULL) {
   298     int n = sscanf(arg1, UINT64_FORMAT, &value);
   299     if (n != 1) {
   300       out->print_cr("flag value must be an unsigned 64-bit integer");
   301       return JNI_ERR;
   302     }
   303   }
   304   bool res = CommandLineFlags::uint64_tAtPut((char*)name, &value, ATTACH_ON_DEMAND);
   305   if (! res) {
   306     out->print_cr("setting flag %s failed", name);
   307   }
   309   return res? JNI_OK : JNI_ERR;
   310 }
   312 // set a string global flag using value from AttachOperation
   313 static jint set_ccstr_flag(const char* name, AttachOperation* op, outputStream* out) {
   314   const char* value;
   315   if ((value = op->arg(1)) == NULL) {
   316     out->print_cr("flag value must be a string");
   317     return JNI_ERR;
   318   }
   319   bool res = CommandLineFlags::ccstrAtPut((char*)name, &value, ATTACH_ON_DEMAND);
   320   if (res) {
   321     FREE_C_HEAP_ARRAY(char, value, mtInternal);
   322   } else {
   323     out->print_cr("setting flag %s failed", name);
   324   }
   326   return res? JNI_OK : JNI_ERR;
   327 }
   329 // Implementation of "setflag" command
   330 static jint set_flag(AttachOperation* op, outputStream* out) {
   332   const char* name = NULL;
   333   if ((name = op->arg(0)) == NULL) {
   334     out->print_cr("flag name is missing");
   335     return JNI_ERR;
   336   }
   338   Flag* f = Flag::find_flag((char*)name, strlen(name));
   339   if (f && f->is_external() && f->is_writeable()) {
   340     if (f->is_bool()) {
   341       return set_bool_flag(name, op, out);
   342     } else if (f->is_intx()) {
   343       return set_intx_flag(name, op, out);
   344     } else if (f->is_uintx()) {
   345       return set_uintx_flag(name, op, out);
   346     } else if (f->is_uint64_t()) {
   347       return set_uint64_t_flag(name, op, out);
   348     } else if (f->is_ccstr()) {
   349       return set_ccstr_flag(name, op, out);
   350     } else {
   351       ShouldNotReachHere();
   352       return JNI_ERR;
   353     }
   354   } else {
   355     return AttachListener::pd_set_flag(op, out);
   356   }
   357 }
   359 // Implementation of "printflag" command
   360 // See also: PrintVMFlagsDCmd class
   361 static jint print_flag(AttachOperation* op, outputStream* out) {
   362   const char* name = NULL;
   363   if ((name = op->arg(0)) == NULL) {
   364     out->print_cr("flag name is missing");
   365     return JNI_ERR;
   366   }
   367   Flag* f = Flag::find_flag((char*)name, strlen(name));
   368   if (f) {
   369     f->print_as_flag(out);
   370     out->print_cr("");
   371   } else {
   372     out->print_cr("no such flag '%s'", name);
   373   }
   374   return JNI_OK;
   375 }
   377 // Table to map operation names to functions.
   379 // names must be of length <= AttachOperation::name_length_max
   380 static AttachOperationFunctionInfo funcs[] = {
   381   { "agentProperties",  get_agent_properties },
   382   { "datadump",         data_dump },
   383   { "dumpheap",         dump_heap },
   384   { "load",             JvmtiExport::load_agent_library },
   385   { "properties",       get_system_properties },
   386   { "threaddump",       thread_dump },
   387   { "inspectheap",      heap_inspection },
   388   { "setflag",          set_flag },
   389   { "printflag",        print_flag },
   390   { "jcmd",             jcmd },
   391   { NULL,               NULL }
   392 };
   396 // The Attach Listener threads services a queue. It dequeues an operation
   397 // from the queue, examines the operation name (command), and dispatches
   398 // to the corresponding function to perform the operation.
   400 static void attach_listener_thread_entry(JavaThread* thread, TRAPS) {
   401   os::set_priority(thread, NearMaxPriority);
   403   thread->record_stack_base_and_size();
   405   if (AttachListener::pd_init() != 0) {
   406     return;
   407   }
   408   AttachListener::set_initialized();
   410   for (;;) {
   411     AttachOperation* op = AttachListener::dequeue();
   412     if (op == NULL) {
   413       return;   // dequeue failed or shutdown
   414     }
   416     ResourceMark rm;
   417     bufferedStream st;
   418     jint res = JNI_OK;
   420     // handle special detachall operation
   421     if (strcmp(op->name(), AttachOperation::detachall_operation_name()) == 0) {
   422       AttachListener::detachall();
   423     } else {
   424       // find the function to dispatch too
   425       AttachOperationFunctionInfo* info = NULL;
   426       for (int i=0; funcs[i].name != NULL; i++) {
   427         const char* name = funcs[i].name;
   428         assert(strlen(name) <= AttachOperation::name_length_max, "operation <= name_length_max");
   429         if (strcmp(op->name(), name) == 0) {
   430           info = &(funcs[i]);
   431           break;
   432         }
   433       }
   435       // check for platform dependent attach operation
   436       if (info == NULL) {
   437         info = AttachListener::pd_find_operation(op->name());
   438       }
   440       if (info != NULL) {
   441         // dispatch to the function that implements this operation
   442         res = (info->func)(op, &st);
   443       } else {
   444         st.print("Operation %s not recognized!", op->name());
   445         res = JNI_ERR;
   446       }
   447     }
   449     // operation complete - send result and output to client
   450     op->complete(res, &st);
   451   }
   452 }
   454 // Starts the Attach Listener thread
   455 void AttachListener::init() {
   456   EXCEPTION_MARK;
   457   Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_Thread(), true, CHECK);
   458   instanceKlassHandle klass (THREAD, k);
   459   instanceHandle thread_oop = klass->allocate_instance_handle(CHECK);
   461   const char thread_name[] = "Attach Listener";
   462   Handle string = java_lang_String::create_from_str(thread_name, CHECK);
   464   // Initialize thread_oop to put it into the system threadGroup
   465   Handle thread_group (THREAD, Universe::system_thread_group());
   466   JavaValue result(T_VOID);
   467   JavaCalls::call_special(&result, thread_oop,
   468                        klass,
   469                        vmSymbols::object_initializer_name(),
   470                        vmSymbols::threadgroup_string_void_signature(),
   471                        thread_group,
   472                        string,
   473                        CHECK);
   475   KlassHandle group(THREAD, SystemDictionary::ThreadGroup_klass());
   476   JavaCalls::call_special(&result,
   477                         thread_group,
   478                         group,
   479                         vmSymbols::add_method_name(),
   480                         vmSymbols::thread_void_signature(),
   481                         thread_oop,             // ARG 1
   482                         CHECK);
   484   { MutexLocker mu(Threads_lock);
   485     JavaThread* listener_thread = new JavaThread(&attach_listener_thread_entry);
   487     // Check that thread and osthread were created
   488     if (listener_thread == NULL || listener_thread->osthread() == NULL) {
   489       vm_exit_during_initialization("java.lang.OutOfMemoryError",
   490                                     "unable to create new native thread");
   491     }
   493     java_lang_Thread::set_thread(thread_oop(), listener_thread);
   494     java_lang_Thread::set_daemon(thread_oop());
   496     listener_thread->set_threadObj(thread_oop());
   497     Threads::add(listener_thread);
   498     Thread::start(listener_thread);
   499   }
   500 }
   502 // Performs clean-up tasks on platforms where we can detect that the last
   503 // client has detached
   504 void AttachListener::detachall() {
   505   // call the platform dependent clean-up
   506   pd_detachall();
   507 }

mercurial