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