src/share/vm/services/attachListener.cpp

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 3900
d2a62e0f25eb
permissions
-rw-r--r--

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

     1 /*
     2  * Copyright (c) 2005, 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 #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 klassOop load_and_initialize_klass(Symbol* sh, TRAPS) {
    48   klassOop 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   klassOop 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 #ifndef SERVICES_KERNEL   // Heap dumping not supported
   174 // Implementation of "dumpheap" command.
   175 // See also: HeapDumpDCmd class
   176 //
   177 // Input arguments :-
   178 //   arg0: Name of the dump file
   179 //   arg1: "-live" or "-all"
   180 jint dump_heap(AttachOperation* op, outputStream* out) {
   181   const char* path = op->arg(0);
   182   if (path == NULL || path[0] == '\0') {
   183     out->print_cr("No dump file specified");
   184   } else {
   185     bool live_objects_only = true;   // default is true to retain the behavior before this change is made
   186     const char* arg1 = op->arg(1);
   187     if (arg1 != NULL && (strlen(arg1) > 0)) {
   188       if (strcmp(arg1, "-all") != 0 && strcmp(arg1, "-live") != 0) {
   189         out->print_cr("Invalid argument to dumpheap operation: %s", arg1);
   190         return JNI_ERR;
   191       }
   192       live_objects_only = strcmp(arg1, "-live") == 0;
   193     }
   195     // Request a full GC before heap dump if live_objects_only = true
   196     // This helps reduces the amount of unreachable objects in the dump
   197     // and makes it easier to browse.
   198     HeapDumper dumper(live_objects_only /* request GC */);
   199     int res = dumper.dump(op->arg(0));
   200     if (res == 0) {
   201       out->print_cr("Heap dump file created");
   202     } else {
   203       // heap dump failed
   204       ResourceMark rm;
   205       char* error = dumper.error_as_C_string();
   206       if (error == NULL) {
   207         out->print_cr("Dump failed - reason unknown");
   208       } else {
   209         out->print_cr("%s", error);
   210       }
   211     }
   212   }
   213   return JNI_OK;
   214 }
   215 #endif // SERVICES_KERNEL
   217 // Implementation of "inspectheap" command
   218 // See also: ClassHistogramDCmd class
   219 //
   220 // Input arguments :-
   221 //   arg0: "-live" or "-all"
   222 static jint heap_inspection(AttachOperation* op, outputStream* out) {
   223   bool live_objects_only = true;   // default is true to retain the behavior before this change is made
   224   const char* arg0 = op->arg(0);
   225   if (arg0 != NULL && (strlen(arg0) > 0)) {
   226     if (strcmp(arg0, "-all") != 0 && strcmp(arg0, "-live") != 0) {
   227       out->print_cr("Invalid argument to inspectheap operation: %s", arg0);
   228       return JNI_ERR;
   229     }
   230     live_objects_only = strcmp(arg0, "-live") == 0;
   231   }
   232   VM_GC_HeapInspection heapop(out, live_objects_only /* request full gc */, true /* need_prologue */);
   233   VMThread::execute(&heapop);
   234   return JNI_OK;
   235 }
   237 // set a boolean global flag using value from AttachOperation
   238 static jint set_bool_flag(const char* name, AttachOperation* op, outputStream* out) {
   239   bool value = true;
   240   const char* arg1;
   241   if ((arg1 = op->arg(1)) != NULL) {
   242     int tmp;
   243     int n = sscanf(arg1, "%d", &tmp);
   244     if (n != 1) {
   245       out->print_cr("flag value must be a boolean (1 or 0)");
   246       return JNI_ERR;
   247     }
   248     value = (tmp != 0);
   249   }
   250   bool res = CommandLineFlags::boolAtPut((char*)name, &value, ATTACH_ON_DEMAND);
   251   if (! res) {
   252     out->print_cr("setting flag %s failed", name);
   253   }
   254   return res? JNI_OK : JNI_ERR;
   255 }
   257 // set a intx global flag using value from AttachOperation
   258 static jint set_intx_flag(const char* name, AttachOperation* op, outputStream* out) {
   259   intx value;
   260   const char* arg1;
   261   if ((arg1 = op->arg(1)) != NULL) {
   262     int n = sscanf(arg1, INTX_FORMAT, &value);
   263     if (n != 1) {
   264       out->print_cr("flag value must be an integer");
   265       return JNI_ERR;
   266     }
   267   }
   268   bool res = CommandLineFlags::intxAtPut((char*)name, &value, ATTACH_ON_DEMAND);
   269   if (! res) {
   270     out->print_cr("setting flag %s failed", name);
   271   }
   273   return res? JNI_OK : JNI_ERR;
   274 }
   276 // set a uintx global flag using value from AttachOperation
   277 static jint set_uintx_flag(const char* name, AttachOperation* op, outputStream* out) {
   278   uintx value;
   279   const char* arg1;
   280   if ((arg1 = op->arg(1)) != NULL) {
   281     int n = sscanf(arg1, UINTX_FORMAT, &value);
   282     if (n != 1) {
   283       out->print_cr("flag value must be an unsigned integer");
   284       return JNI_ERR;
   285     }
   286   }
   287   bool res = CommandLineFlags::uintxAtPut((char*)name, &value, ATTACH_ON_DEMAND);
   288   if (! res) {
   289     out->print_cr("setting flag %s failed", name);
   290   }
   292   return res? JNI_OK : JNI_ERR;
   293 }
   295 // set a uint64_t global flag using value from AttachOperation
   296 static jint set_uint64_t_flag(const char* name, AttachOperation* op, outputStream* out) {
   297   uint64_t value;
   298   const char* arg1;
   299   if ((arg1 = op->arg(1)) != NULL) {
   300     int n = sscanf(arg1, UINT64_FORMAT, &value);
   301     if (n != 1) {
   302       out->print_cr("flag value must be an unsigned 64-bit integer");
   303       return JNI_ERR;
   304     }
   305   }
   306   bool res = CommandLineFlags::uint64_tAtPut((char*)name, &value, ATTACH_ON_DEMAND);
   307   if (! res) {
   308     out->print_cr("setting flag %s failed", name);
   309   }
   311   return res? JNI_OK : JNI_ERR;
   312 }
   314 // set a string global flag using value from AttachOperation
   315 static jint set_ccstr_flag(const char* name, AttachOperation* op, outputStream* out) {
   316   const char* value;
   317   if ((value = op->arg(1)) == NULL) {
   318     out->print_cr("flag value must be a string");
   319     return JNI_ERR;
   320   }
   321   bool res = CommandLineFlags::ccstrAtPut((char*)name, &value, ATTACH_ON_DEMAND);
   322   if (res) {
   323     FREE_C_HEAP_ARRAY(char, value);
   324   } else {
   325     out->print_cr("setting flag %s failed", name);
   326   }
   328   return res? JNI_OK : JNI_ERR;
   329 }
   331 // Implementation of "setflag" command
   332 static jint set_flag(AttachOperation* op, outputStream* out) {
   334   const char* name = NULL;
   335   if ((name = op->arg(0)) == NULL) {
   336     out->print_cr("flag name is missing");
   337     return JNI_ERR;
   338   }
   340   Flag* f = Flag::find_flag((char*)name, strlen(name));
   341   if (f && f->is_external() && f->is_writeable()) {
   342     if (f->is_bool()) {
   343       return set_bool_flag(name, op, out);
   344     } else if (f->is_intx()) {
   345       return set_intx_flag(name, op, out);
   346     } else if (f->is_uintx()) {
   347       return set_uintx_flag(name, op, out);
   348     } else if (f->is_uint64_t()) {
   349       return set_uint64_t_flag(name, op, out);
   350     } else if (f->is_ccstr()) {
   351       return set_ccstr_flag(name, op, out);
   352     } else {
   353       ShouldNotReachHere();
   354       return JNI_ERR;
   355     }
   356   } else {
   357     return AttachListener::pd_set_flag(op, out);
   358   }
   359 }
   361 // Implementation of "printflag" command
   362 // See also: PrintVMFlagsDCmd class
   363 static jint print_flag(AttachOperation* op, outputStream* out) {
   364   const char* name = NULL;
   365   if ((name = op->arg(0)) == NULL) {
   366     out->print_cr("flag name is missing");
   367     return JNI_ERR;
   368   }
   369   Flag* f = Flag::find_flag((char*)name, strlen(name));
   370   if (f) {
   371     f->print_as_flag(out);
   372     out->print_cr("");
   373   } else {
   374     out->print_cr("no such flag '%s'", name);
   375   }
   376   return JNI_OK;
   377 }
   379 // Table to map operation names to functions.
   381 // names must be of length <= AttachOperation::name_length_max
   382 static AttachOperationFunctionInfo funcs[] = {
   383   { "agentProperties",  get_agent_properties },
   384   { "datadump",         data_dump },
   385 #ifndef SERVICES_KERNEL
   386   { "dumpheap",         dump_heap },
   387 #endif  // SERVICES_KERNEL
   388   { "load",             JvmtiExport::load_agent_library },
   389   { "properties",       get_system_properties },
   390   { "threaddump",       thread_dump },
   391   { "inspectheap",      heap_inspection },
   392   { "setflag",          set_flag },
   393   { "printflag",        print_flag },
   394   { "jcmd",             jcmd },
   395   { NULL,               NULL }
   396 };
   400 // The Attach Listener threads services a queue. It dequeues an operation
   401 // from the queue, examines the operation name (command), and dispatches
   402 // to the corresponding function to perform the operation.
   404 static void attach_listener_thread_entry(JavaThread* thread, TRAPS) {
   405   os::set_priority(thread, NearMaxPriority);
   407   if (AttachListener::pd_init() != 0) {
   408     return;
   409   }
   410   AttachListener::set_initialized();
   412   for (;;) {
   413     AttachOperation* op = AttachListener::dequeue();
   414     if (op == NULL) {
   415       return;   // dequeue failed or shutdown
   416     }
   418     ResourceMark rm;
   419     bufferedStream st;
   420     jint res = JNI_OK;
   422     // handle special detachall operation
   423     if (strcmp(op->name(), AttachOperation::detachall_operation_name()) == 0) {
   424       AttachListener::detachall();
   425     } else {
   426       // find the function to dispatch too
   427       AttachOperationFunctionInfo* info = NULL;
   428       for (int i=0; funcs[i].name != NULL; i++) {
   429         const char* name = funcs[i].name;
   430         assert(strlen(name) <= AttachOperation::name_length_max, "operation <= name_length_max");
   431         if (strcmp(op->name(), name) == 0) {
   432           info = &(funcs[i]);
   433           break;
   434         }
   435       }
   437       // check for platform dependent attach operation
   438       if (info == NULL) {
   439         info = AttachListener::pd_find_operation(op->name());
   440       }
   442       if (info != NULL) {
   443         // dispatch to the function that implements this operation
   444         res = (info->func)(op, &st);
   445       } else {
   446         st.print("Operation %s not recognized!", op->name());
   447         res = JNI_ERR;
   448       }
   449     }
   451     // operation complete - send result and output to client
   452     op->complete(res, &st);
   453   }
   454 }
   456 // Starts the Attach Listener thread
   457 void AttachListener::init() {
   458   EXCEPTION_MARK;
   459   klassOop k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_Thread(), true, CHECK);
   460   instanceKlassHandle klass (THREAD, k);
   461   instanceHandle thread_oop = klass->allocate_instance_handle(CHECK);
   463   const char thread_name[] = "Attach Listener";
   464   Handle string = java_lang_String::create_from_str(thread_name, CHECK);
   466   // Initialize thread_oop to put it into the system threadGroup
   467   Handle thread_group (THREAD, Universe::system_thread_group());
   468   JavaValue result(T_VOID);
   469   JavaCalls::call_special(&result, thread_oop,
   470                        klass,
   471                        vmSymbols::object_initializer_name(),
   472                        vmSymbols::threadgroup_string_void_signature(),
   473                        thread_group,
   474                        string,
   475                        CHECK);
   477   KlassHandle group(THREAD, SystemDictionary::ThreadGroup_klass());
   478   JavaCalls::call_special(&result,
   479                         thread_group,
   480                         group,
   481                         vmSymbols::add_method_name(),
   482                         vmSymbols::thread_void_signature(),
   483                         thread_oop,             // ARG 1
   484                         CHECK);
   486   { MutexLocker mu(Threads_lock);
   487     JavaThread* listener_thread = new JavaThread(&attach_listener_thread_entry);
   489     // Check that thread and osthread were created
   490     if (listener_thread == NULL || listener_thread->osthread() == NULL) {
   491       vm_exit_during_initialization("java.lang.OutOfMemoryError",
   492                                     "unable to create new native thread");
   493     }
   495     java_lang_Thread::set_thread(thread_oop(), listener_thread);
   496     java_lang_Thread::set_daemon(thread_oop());
   498     listener_thread->set_threadObj(thread_oop());
   499     Threads::add(listener_thread);
   500     Thread::start(listener_thread);
   501   }
   502 }
   504 // Performs clean-up tasks on platforms where we can detect that the last
   505 // client has detached
   506 void AttachListener::detachall() {
   507   // call the platform dependent clean-up
   508   pd_detachall();
   509 }

mercurial