src/share/vm/services/attachListener.cpp

Tue, 23 Nov 2010 13:22:55 -0800

author
stefank
date
Tue, 23 Nov 2010 13:22:55 -0800
changeset 2314
f95d63e2154a
parent 1907
c18cbe5936b8
child 2497
3582bf76420e
permissions
-rw-r--r--

6989984: Use standard include model for Hospot
Summary: Replaced MakeDeps and the includeDB files with more standardized solutions.
Reviewed-by: coleenp, kvn, kamg

     1 /*
     2  * Copyright (c) 2005, 2010, 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/heapDumper.hpp"
    39 volatile bool AttachListener::_initialized;
    41 // Implementation of "properties" command.
    42 //
    43 // Invokes sun.misc.VMSupport.serializePropertiesToByteArray to serialize
    44 // the system properties into a byte array.
    46 static klassOop load_and_initialize_klass(symbolHandle sh, TRAPS) {
    47   klassOop k = SystemDictionary::resolve_or_fail(sh, true, CHECK_NULL);
    48   instanceKlassHandle ik (THREAD, k);
    49   if (ik->should_be_initialized()) {
    50     ik->initialize(CHECK_NULL);
    51   }
    52   return ik();
    53 }
    55 static jint get_properties(AttachOperation* op, outputStream* out, symbolHandle serializePropertiesMethod) {
    56   Thread* THREAD = Thread::current();
    57   HandleMark hm;
    59   // load sun.misc.VMSupport
    60   symbolHandle klass = vmSymbolHandles::sun_misc_VMSupport();
    61   klassOop k = load_and_initialize_klass(klass, THREAD);
    62   if (HAS_PENDING_EXCEPTION) {
    63     java_lang_Throwable::print(PENDING_EXCEPTION, out);
    64     CLEAR_PENDING_EXCEPTION;
    65     return JNI_ERR;
    66   }
    67   instanceKlassHandle ik(THREAD, k);
    69   // invoke the serializePropertiesToByteArray method
    70   JavaValue result(T_OBJECT);
    71   JavaCallArguments args;
    74   symbolHandle signature = vmSymbolHandles::serializePropertiesToByteArray_signature();
    75   JavaCalls::call_static(&result,
    76                            ik,
    77                            serializePropertiesMethod,
    78                            signature,
    79                            &args,
    80                            THREAD);
    81   if (HAS_PENDING_EXCEPTION) {
    82     java_lang_Throwable::print(PENDING_EXCEPTION, out);
    83     CLEAR_PENDING_EXCEPTION;
    84     return JNI_ERR;
    85   }
    87   // The result should be a [B
    88   oop res = (oop)result.get_jobject();
    89   assert(res->is_typeArray(), "just checking");
    90   assert(typeArrayKlass::cast(res->klass())->element_type() == T_BYTE, "just checking");
    92   // copy the bytes to the output stream
    93   typeArrayOop ba = typeArrayOop(res);
    94   jbyte* addr = typeArrayOop(res)->byte_at_addr(0);
    95   out->print_raw((const char*)addr, ba->length());
    97   return JNI_OK;
    98 }
   100 // Implementation of "properties" command.
   101 static jint get_system_properties(AttachOperation* op, outputStream* out) {
   102   return get_properties(op, out, vmSymbolHandles::serializePropertiesToByteArray_name());
   103 }
   105 // Implementation of "agent_properties" command.
   106 static jint get_agent_properties(AttachOperation* op, outputStream* out) {
   107   return get_properties(op, out, vmSymbolHandles::serializeAgentPropertiesToByteArray_name());
   108 }
   110 // Implementation of "datadump" command.
   111 //
   112 // Raises a SIGBREAK signal so that VM dump threads, does deadlock detection,
   113 // etc. In theory this command should only post a DataDumpRequest to any
   114 // JVMTI environment that has enabled this event. However it's useful to
   115 // trigger the SIGBREAK handler.
   117 static jint data_dump(AttachOperation* op, outputStream* out) {
   118   if (!ReduceSignalUsage) {
   119     AttachListener::pd_data_dump();
   120   } else {
   121     if (JvmtiExport::should_post_data_dump()) {
   122       JvmtiExport::post_data_dump();
   123     }
   124   }
   125   return JNI_OK;
   126 }
   128 // Implementation of "threaddump" command - essentially a remote ctrl-break
   129 //
   130 static jint thread_dump(AttachOperation* op, outputStream* out) {
   131   bool print_concurrent_locks = false;
   132   if (op->arg(0) != NULL && strcmp(op->arg(0), "-l") == 0) {
   133     print_concurrent_locks = true;
   134   }
   136   // thread stacks
   137   VM_PrintThreads op1(out, print_concurrent_locks);
   138   VMThread::execute(&op1);
   140   // JNI global handles
   141   VM_PrintJNI op2(out);
   142   VMThread::execute(&op2);
   144   // Deadlock detection
   145   VM_FindDeadlocks op3(out);
   146   VMThread::execute(&op3);
   148   return JNI_OK;
   149 }
   151 #ifndef SERVICES_KERNEL   // Heap dumping not supported
   152 // Implementation of "dumpheap" command.
   153 //
   154 // Input arguments :-
   155 //   arg0: Name of the dump file
   156 //   arg1: "-live" or "-all"
   157 jint dump_heap(AttachOperation* op, outputStream* out) {
   158   const char* path = op->arg(0);
   159   if (path == NULL || path[0] == '\0') {
   160     out->print_cr("No dump file specified");
   161   } else {
   162     bool live_objects_only = true;   // default is true to retain the behavior before this change is made
   163     const char* arg1 = op->arg(1);
   164     if (arg1 != NULL && (strlen(arg1) > 0)) {
   165       if (strcmp(arg1, "-all") != 0 && strcmp(arg1, "-live") != 0) {
   166         out->print_cr("Invalid argument to dumpheap operation: %s", arg1);
   167         return JNI_ERR;
   168       }
   169       live_objects_only = strcmp(arg1, "-live") == 0;
   170     }
   172     // Request a full GC before heap dump if live_objects_only = true
   173     // This helps reduces the amount of unreachable objects in the dump
   174     // and makes it easier to browse.
   175     HeapDumper dumper(live_objects_only /* request GC */);
   176     int res = dumper.dump(op->arg(0));
   177     if (res == 0) {
   178       out->print_cr("Heap dump file created");
   179     } else {
   180       // heap dump failed
   181       ResourceMark rm;
   182       char* error = dumper.error_as_C_string();
   183       if (error == NULL) {
   184         out->print_cr("Dump failed - reason unknown");
   185       } else {
   186         out->print_cr("%s", error);
   187       }
   188     }
   189   }
   190   return JNI_OK;
   191 }
   192 #endif // SERVICES_KERNEL
   194 // Implementation of "inspectheap" command
   195 //
   196 // Input arguments :-
   197 //   arg0: "-live" or "-all"
   198 static jint heap_inspection(AttachOperation* op, outputStream* out) {
   199   bool live_objects_only = true;   // default is true to retain the behavior before this change is made
   200   const char* arg0 = op->arg(0);
   201   if (arg0 != NULL && (strlen(arg0) > 0)) {
   202     if (strcmp(arg0, "-all") != 0 && strcmp(arg0, "-live") != 0) {
   203       out->print_cr("Invalid argument to inspectheap operation: %s", arg0);
   204       return JNI_ERR;
   205     }
   206     live_objects_only = strcmp(arg0, "-live") == 0;
   207   }
   208   VM_GC_HeapInspection heapop(out, live_objects_only /* request full gc */, true /* need_prologue */);
   209   VMThread::execute(&heapop);
   210   return JNI_OK;
   211 }
   213 // set a boolean global flag using value from AttachOperation
   214 static jint set_bool_flag(const char* name, AttachOperation* op, outputStream* out) {
   215   bool value = true;
   216   const char* arg1;
   217   if ((arg1 = op->arg(1)) != NULL) {
   218     int tmp;
   219     int n = sscanf(arg1, "%d", &tmp);
   220     if (n != 1) {
   221       out->print_cr("flag value must be a boolean (1 or 0)");
   222       return JNI_ERR;
   223     }
   224     value = (tmp != 0);
   225   }
   226   bool res = CommandLineFlags::boolAtPut((char*)name, &value, ATTACH_ON_DEMAND);
   227   if (! res) {
   228     out->print_cr("setting flag %s failed", name);
   229   }
   230   return res? JNI_OK : JNI_ERR;
   231 }
   233 // set a intx global flag using value from AttachOperation
   234 static jint set_intx_flag(const char* name, AttachOperation* op, outputStream* out) {
   235   intx value;
   236   const char* arg1;
   237   if ((arg1 = op->arg(1)) != NULL) {
   238     int n = sscanf(arg1, INTX_FORMAT, &value);
   239     if (n != 1) {
   240       out->print_cr("flag value must be an integer");
   241       return JNI_ERR;
   242     }
   243   }
   244   bool res = CommandLineFlags::intxAtPut((char*)name, &value, ATTACH_ON_DEMAND);
   245   if (! res) {
   246     out->print_cr("setting flag %s failed", name);
   247   }
   249   return res? JNI_OK : JNI_ERR;
   250 }
   252 // set a uintx global flag using value from AttachOperation
   253 static jint set_uintx_flag(const char* name, AttachOperation* op, outputStream* out) {
   254   uintx value;
   255   const char* arg1;
   256   if ((arg1 = op->arg(1)) != NULL) {
   257     int n = sscanf(arg1, UINTX_FORMAT, &value);
   258     if (n != 1) {
   259       out->print_cr("flag value must be an unsigned integer");
   260       return JNI_ERR;
   261     }
   262   }
   263   bool res = CommandLineFlags::uintxAtPut((char*)name, &value, ATTACH_ON_DEMAND);
   264   if (! res) {
   265     out->print_cr("setting flag %s failed", name);
   266   }
   268   return res? JNI_OK : JNI_ERR;
   269 }
   271 // set a uint64_t global flag using value from AttachOperation
   272 static jint set_uint64_t_flag(const char* name, AttachOperation* op, outputStream* out) {
   273   uint64_t value;
   274   const char* arg1;
   275   if ((arg1 = op->arg(1)) != NULL) {
   276     int n = sscanf(arg1, UINT64_FORMAT, &value);
   277     if (n != 1) {
   278       out->print_cr("flag value must be an unsigned 64-bit integer");
   279       return JNI_ERR;
   280     }
   281   }
   282   bool res = CommandLineFlags::uint64_tAtPut((char*)name, &value, ATTACH_ON_DEMAND);
   283   if (! res) {
   284     out->print_cr("setting flag %s failed", name);
   285   }
   287   return res? JNI_OK : JNI_ERR;
   288 }
   290 // set a string global flag using value from AttachOperation
   291 static jint set_ccstr_flag(const char* name, AttachOperation* op, outputStream* out) {
   292   const char* value;
   293   if ((value = op->arg(1)) == NULL) {
   294     out->print_cr("flag value must be a string");
   295     return JNI_ERR;
   296   }
   297   bool res = CommandLineFlags::ccstrAtPut((char*)name, &value, ATTACH_ON_DEMAND);
   298   if (res) {
   299     FREE_C_HEAP_ARRAY(char, value);
   300   } else {
   301     out->print_cr("setting flag %s failed", name);
   302   }
   304   return res? JNI_OK : JNI_ERR;
   305 }
   307 // Implementation of "setflag" command
   308 static jint set_flag(AttachOperation* op, outputStream* out) {
   310   const char* name = NULL;
   311   if ((name = op->arg(0)) == NULL) {
   312     out->print_cr("flag name is missing");
   313     return JNI_ERR;
   314   }
   316   Flag* f = Flag::find_flag((char*)name, strlen(name));
   317   if (f && f->is_external() && f->is_writeable()) {
   318     if (f->is_bool()) {
   319       return set_bool_flag(name, op, out);
   320     } else if (f->is_intx()) {
   321       return set_intx_flag(name, op, out);
   322     } else if (f->is_uintx()) {
   323       return set_uintx_flag(name, op, out);
   324     } else if (f->is_uint64_t()) {
   325       return set_uint64_t_flag(name, op, out);
   326     } else if (f->is_ccstr()) {
   327       return set_ccstr_flag(name, op, out);
   328     } else {
   329       ShouldNotReachHere();
   330       return JNI_ERR;
   331     }
   332   } else {
   333     return AttachListener::pd_set_flag(op, out);
   334   }
   335 }
   337 // Implementation of "printflag" command
   338 static jint print_flag(AttachOperation* op, outputStream* out) {
   339   const char* name = NULL;
   340   if ((name = op->arg(0)) == NULL) {
   341     out->print_cr("flag name is missing");
   342     return JNI_ERR;
   343   }
   344   Flag* f = Flag::find_flag((char*)name, strlen(name));
   345   if (f) {
   346     f->print_as_flag(out);
   347     out->print_cr("");
   348   } else {
   349     out->print_cr("no such flag '%s'", name);
   350   }
   351   return JNI_OK;
   352 }
   354 // Table to map operation names to functions.
   356 // names must be of length <= AttachOperation::name_length_max
   357 static AttachOperationFunctionInfo funcs[] = {
   358   { "agentProperties",  get_agent_properties },
   359   { "datadump",         data_dump },
   360 #ifndef SERVICES_KERNEL
   361   { "dumpheap",         dump_heap },
   362 #endif  // SERVICES_KERNEL
   363   { "load",             JvmtiExport::load_agent_library },
   364   { "properties",       get_system_properties },
   365   { "threaddump",       thread_dump },
   366   { "inspectheap",      heap_inspection },
   367   { "setflag",          set_flag },
   368   { "printflag",        print_flag },
   369   { NULL,               NULL }
   370 };
   374 // The Attach Listener threads services a queue. It dequeues an operation
   375 // from the queue, examines the operation name (command), and dispatches
   376 // to the corresponding function to perform the operation.
   378 static void attach_listener_thread_entry(JavaThread* thread, TRAPS) {
   379   os::set_priority(thread, NearMaxPriority);
   381   if (AttachListener::pd_init() != 0) {
   382     return;
   383   }
   384   AttachListener::set_initialized();
   386   for (;;) {
   387     AttachOperation* op = AttachListener::dequeue();
   388     if (op == NULL) {
   389       return;   // dequeue failed or shutdown
   390     }
   392     ResourceMark rm;
   393     bufferedStream st;
   394     jint res = JNI_OK;
   396     // handle special detachall operation
   397     if (strcmp(op->name(), AttachOperation::detachall_operation_name()) == 0) {
   398       AttachListener::detachall();
   399     } else {
   400       // find the function to dispatch too
   401       AttachOperationFunctionInfo* info = NULL;
   402       for (int i=0; funcs[i].name != NULL; i++) {
   403         const char* name = funcs[i].name;
   404         assert(strlen(name) <= AttachOperation::name_length_max, "operation <= name_length_max");
   405         if (strcmp(op->name(), name) == 0) {
   406           info = &(funcs[i]);
   407           break;
   408         }
   409       }
   411       // check for platform dependent attach operation
   412       if (info == NULL) {
   413         info = AttachListener::pd_find_operation(op->name());
   414       }
   416       if (info != NULL) {
   417         // dispatch to the function that implements this operation
   418         res = (info->func)(op, &st);
   419       } else {
   420         st.print("Operation %s not recognized!", op->name());
   421         res = JNI_ERR;
   422       }
   423     }
   425     // operation complete - send result and output to client
   426     op->complete(res, &st);
   427   }
   428 }
   430 // Starts the Attach Listener thread
   431 void AttachListener::init() {
   432   EXCEPTION_MARK;
   433   klassOop k = SystemDictionary::resolve_or_fail(vmSymbolHandles::java_lang_Thread(), true, CHECK);
   434   instanceKlassHandle klass (THREAD, k);
   435   instanceHandle thread_oop = klass->allocate_instance_handle(CHECK);
   437   const char thread_name[] = "Attach Listener";
   438   Handle string = java_lang_String::create_from_str(thread_name, CHECK);
   440   // Initialize thread_oop to put it into the system threadGroup
   441   Handle thread_group (THREAD, Universe::system_thread_group());
   442   JavaValue result(T_VOID);
   443   JavaCalls::call_special(&result, thread_oop,
   444                        klass,
   445                        vmSymbolHandles::object_initializer_name(),
   446                        vmSymbolHandles::threadgroup_string_void_signature(),
   447                        thread_group,
   448                        string,
   449                        CHECK);
   451   KlassHandle group(THREAD, SystemDictionary::ThreadGroup_klass());
   452   JavaCalls::call_special(&result,
   453                         thread_group,
   454                         group,
   455                         vmSymbolHandles::add_method_name(),
   456                         vmSymbolHandles::thread_void_signature(),
   457                         thread_oop,             // ARG 1
   458                         CHECK);
   460   { MutexLocker mu(Threads_lock);
   461     JavaThread* listener_thread = new JavaThread(&attach_listener_thread_entry);
   463     // Check that thread and osthread were created
   464     if (listener_thread == NULL || listener_thread->osthread() == NULL) {
   465       vm_exit_during_initialization("java.lang.OutOfMemoryError",
   466                                     "unable to create new native thread");
   467     }
   469     java_lang_Thread::set_thread(thread_oop(), listener_thread);
   470     java_lang_Thread::set_daemon(thread_oop());
   472     listener_thread->set_threadObj(thread_oop());
   473     Threads::add(listener_thread);
   474     Thread::start(listener_thread);
   475   }
   476 }
   478 // Performs clean-up tasks on platforms where we can detect that the last
   479 // client has detached
   480 void AttachListener::detachall() {
   481   // call the platform dependent clean-up
   482   pd_detachall();
   483 }

mercurial