src/share/vm/services/attachListener.cpp

Wed, 27 Aug 2014 08:19:12 -0400

author
zgu
date
Wed, 27 Aug 2014 08:19:12 -0400
changeset 7074
833b0f92429a
parent 6680
78bbf4d43a14
child 6876
710a3c8b516e
child 7128
2545e461115b
permissions
-rw-r--r--

8046598: Scalable Native memory tracking development
Summary: Enhance scalability of native memory tracking
Reviewed-by: coleenp, ctornqvi, gtriantafill

     1 /*
     2  * Copyright (c) 2005, 2014, 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(DCmd_Source_AttachAPI, 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 */);
   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, Flag::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, Flag::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   }
   286   if (strncmp(name, "MaxHeapFreeRatio", 17) == 0) {
   287     FormatBuffer<80> err_msg("%s", "");
   288     if (!Arguments::verify_MaxHeapFreeRatio(err_msg, value)) {
   289       out->print_cr("%s", err_msg.buffer());
   290       return JNI_ERR;
   291     }
   292   } else if (strncmp(name, "MinHeapFreeRatio", 17) == 0) {
   293     FormatBuffer<80> err_msg("%s", "");
   294     if (!Arguments::verify_MinHeapFreeRatio(err_msg, value)) {
   295       out->print_cr("%s", err_msg.buffer());
   296       return JNI_ERR;
   297     }
   298   }
   299   bool res = CommandLineFlags::uintxAtPut((char*)name, &value, Flag::ATTACH_ON_DEMAND);
   300   if (! res) {
   301     out->print_cr("setting flag %s failed", name);
   302   }
   304   return res? JNI_OK : JNI_ERR;
   305 }
   307 // set a uint64_t global flag using value from AttachOperation
   308 static jint set_uint64_t_flag(const char* name, AttachOperation* op, outputStream* out) {
   309   uint64_t value;
   310   const char* arg1;
   311   if ((arg1 = op->arg(1)) != NULL) {
   312     int n = sscanf(arg1, UINT64_FORMAT, &value);
   313     if (n != 1) {
   314       out->print_cr("flag value must be an unsigned 64-bit integer");
   315       return JNI_ERR;
   316     }
   317   }
   318   bool res = CommandLineFlags::uint64_tAtPut((char*)name, &value, Flag::ATTACH_ON_DEMAND);
   319   if (! res) {
   320     out->print_cr("setting flag %s failed", name);
   321   }
   323   return res? JNI_OK : JNI_ERR;
   324 }
   326 // set a string global flag using value from AttachOperation
   327 static jint set_ccstr_flag(const char* name, AttachOperation* op, outputStream* out) {
   328   const char* value;
   329   if ((value = op->arg(1)) == NULL) {
   330     out->print_cr("flag value must be a string");
   331     return JNI_ERR;
   332   }
   333   bool res = CommandLineFlags::ccstrAtPut((char*)name, &value, Flag::ATTACH_ON_DEMAND);
   334   if (res) {
   335     FREE_C_HEAP_ARRAY(char, value, mtInternal);
   336   } else {
   337     out->print_cr("setting flag %s failed", name);
   338   }
   340   return res? JNI_OK : JNI_ERR;
   341 }
   343 // Implementation of "setflag" command
   344 static jint set_flag(AttachOperation* op, outputStream* out) {
   346   const char* name = NULL;
   347   if ((name = op->arg(0)) == NULL) {
   348     out->print_cr("flag name is missing");
   349     return JNI_ERR;
   350   }
   352   Flag* f = Flag::find_flag((char*)name, strlen(name));
   353   if (f && f->is_external() && f->is_writeable()) {
   354     if (f->is_bool()) {
   355       return set_bool_flag(name, op, out);
   356     } else if (f->is_intx()) {
   357       return set_intx_flag(name, op, out);
   358     } else if (f->is_uintx()) {
   359       return set_uintx_flag(name, op, out);
   360     } else if (f->is_uint64_t()) {
   361       return set_uint64_t_flag(name, op, out);
   362     } else if (f->is_ccstr()) {
   363       return set_ccstr_flag(name, op, out);
   364     } else {
   365       ShouldNotReachHere();
   366       return JNI_ERR;
   367     }
   368   } else {
   369     return AttachListener::pd_set_flag(op, out);
   370   }
   371 }
   373 // Implementation of "printflag" command
   374 // See also: PrintVMFlagsDCmd class
   375 static jint print_flag(AttachOperation* op, outputStream* out) {
   376   const char* name = NULL;
   377   if ((name = op->arg(0)) == NULL) {
   378     out->print_cr("flag name is missing");
   379     return JNI_ERR;
   380   }
   381   Flag* f = Flag::find_flag((char*)name, strlen(name));
   382   if (f) {
   383     f->print_as_flag(out);
   384     out->cr();
   385   } else {
   386     out->print_cr("no such flag '%s'", name);
   387   }
   388   return JNI_OK;
   389 }
   391 // Table to map operation names to functions.
   393 // names must be of length <= AttachOperation::name_length_max
   394 static AttachOperationFunctionInfo funcs[] = {
   395   { "agentProperties",  get_agent_properties },
   396   { "datadump",         data_dump },
   397   { "dumpheap",         dump_heap },
   398   { "load",             JvmtiExport::load_agent_library },
   399   { "properties",       get_system_properties },
   400   { "threaddump",       thread_dump },
   401   { "inspectheap",      heap_inspection },
   402   { "setflag",          set_flag },
   403   { "printflag",        print_flag },
   404   { "jcmd",             jcmd },
   405   { NULL,               NULL }
   406 };
   410 // The Attach Listener threads services a queue. It dequeues an operation
   411 // from the queue, examines the operation name (command), and dispatches
   412 // to the corresponding function to perform the operation.
   414 static void attach_listener_thread_entry(JavaThread* thread, TRAPS) {
   415   os::set_priority(thread, NearMaxPriority);
   417   thread->record_stack_base_and_size();
   419   if (AttachListener::pd_init() != 0) {
   420     return;
   421   }
   422   AttachListener::set_initialized();
   424   for (;;) {
   425     AttachOperation* op = AttachListener::dequeue();
   426     if (op == NULL) {
   427       return;   // dequeue failed or shutdown
   428     }
   430     ResourceMark rm;
   431     bufferedStream st;
   432     jint res = JNI_OK;
   434     // handle special detachall operation
   435     if (strcmp(op->name(), AttachOperation::detachall_operation_name()) == 0) {
   436       AttachListener::detachall();
   437     } else {
   438       // find the function to dispatch too
   439       AttachOperationFunctionInfo* info = NULL;
   440       for (int i=0; funcs[i].name != NULL; i++) {
   441         const char* name = funcs[i].name;
   442         assert(strlen(name) <= AttachOperation::name_length_max, "operation <= name_length_max");
   443         if (strcmp(op->name(), name) == 0) {
   444           info = &(funcs[i]);
   445           break;
   446         }
   447       }
   449       // check for platform dependent attach operation
   450       if (info == NULL) {
   451         info = AttachListener::pd_find_operation(op->name());
   452       }
   454       if (info != NULL) {
   455         // dispatch to the function that implements this operation
   456         res = (info->func)(op, &st);
   457       } else {
   458         st.print("Operation %s not recognized!", op->name());
   459         res = JNI_ERR;
   460       }
   461     }
   463     // operation complete - send result and output to client
   464     op->complete(res, &st);
   465   }
   466 }
   468 // Starts the Attach Listener thread
   469 void AttachListener::init() {
   470   EXCEPTION_MARK;
   471   Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_Thread(), true, CHECK);
   472   instanceKlassHandle klass (THREAD, k);
   473   instanceHandle thread_oop = klass->allocate_instance_handle(CHECK);
   475   const char thread_name[] = "Attach Listener";
   476   Handle string = java_lang_String::create_from_str(thread_name, CHECK);
   478   // Initialize thread_oop to put it into the system threadGroup
   479   Handle thread_group (THREAD, Universe::system_thread_group());
   480   JavaValue result(T_VOID);
   481   JavaCalls::call_special(&result, thread_oop,
   482                        klass,
   483                        vmSymbols::object_initializer_name(),
   484                        vmSymbols::threadgroup_string_void_signature(),
   485                        thread_group,
   486                        string,
   487                        THREAD);
   489   if (HAS_PENDING_EXCEPTION) {
   490     tty->print_cr("Exception in VM (AttachListener::init) : ");
   491     java_lang_Throwable::print(PENDING_EXCEPTION, tty);
   492     tty->cr();
   494     CLEAR_PENDING_EXCEPTION;
   496     return;
   497   }
   499   KlassHandle group(THREAD, SystemDictionary::ThreadGroup_klass());
   500   JavaCalls::call_special(&result,
   501                         thread_group,
   502                         group,
   503                         vmSymbols::add_method_name(),
   504                         vmSymbols::thread_void_signature(),
   505                         thread_oop,             // ARG 1
   506                         THREAD);
   508   if (HAS_PENDING_EXCEPTION) {
   509     tty->print_cr("Exception in VM (AttachListener::init) : ");
   510     java_lang_Throwable::print(PENDING_EXCEPTION, tty);
   511     tty->cr();
   513     CLEAR_PENDING_EXCEPTION;
   515     return;
   516   }
   518   { MutexLocker mu(Threads_lock);
   519     JavaThread* listener_thread = new JavaThread(&attach_listener_thread_entry);
   521     // Check that thread and osthread were created
   522     if (listener_thread == NULL || listener_thread->osthread() == NULL) {
   523       vm_exit_during_initialization("java.lang.OutOfMemoryError",
   524                                     "unable to create new native thread");
   525     }
   527     java_lang_Thread::set_thread(thread_oop(), listener_thread);
   528     java_lang_Thread::set_daemon(thread_oop());
   530     listener_thread->set_threadObj(thread_oop());
   531     Threads::add(listener_thread);
   532     Thread::start(listener_thread);
   533   }
   534 }
   536 // Performs clean-up tasks on platforms where we can detect that the last
   537 // client has detached
   538 void AttachListener::detachall() {
   539   // call the platform dependent clean-up
   540   pd_detachall();
   541 }

mercurial