# HG changeset patch # User sla # Date 1409822468 -7200 # Node ID 41332d860d6a4a65dc4d386b20027b89a295ba0e # Parent fa1e0d1c960f8c7a8023d040dd616b40e523d85d 8057535: add a thread extension class Reviewed-by: mgerdin, bdelsart, jcoomes diff -r fa1e0d1c960f -r 41332d860d6a hotspot/src/share/vm/runtime/thread.cpp --- a/hotspot/src/share/vm/runtime/thread.cpp Mon Sep 22 16:22:21 2014 +0200 +++ b/hotspot/src/share/vm/runtime/thread.cpp Thu Sep 04 11:21:08 2014 +0200 @@ -826,6 +826,7 @@ st->print("os_prio=%d ", os_prio); } st->print("tid=" INTPTR_FORMAT " ", this); + ext().print_on(st); osthread()->print_on(st); } debug_only(if (WizardMode) print_owned_locks_on(st);) @@ -2964,6 +2965,8 @@ // Push the Java priority down to the native thread; needs Threads_lock Thread::set_priority(this, prio); + prepare_ext(); + // Add the new thread to the Threads list and set it in motion. // We must have threads lock in order to call Threads::add. // It is crucial that we do not block before the thread is @@ -3795,6 +3798,24 @@ } } +JavaThread* Threads::find_java_thread_from_java_tid(jlong java_tid) { + assert(Threads_lock->owned_by_self(), "Must hold Threads_lock"); + + JavaThread* java_thread = NULL; + // Sequential search for now. Need to do better optimization later. + for (JavaThread* thread = Threads::first(); thread != NULL; thread = thread->next()) { + oop tobj = thread->threadObj(); + if (!thread->is_exiting() && + tobj != NULL && + java_tid == java_lang_Thread::thread_id(tobj)) { + java_thread = thread; + break; + } + } + return java_thread; +} + + // Last thread running calls java.lang.Shutdown.shutdown() void JavaThread::invoke_shutdown_hooks() { HandleMark hm(this); diff -r fa1e0d1c960f -r 41332d860d6a hotspot/src/share/vm/runtime/thread.hpp --- a/hotspot/src/share/vm/runtime/thread.hpp Mon Sep 22 16:22:21 2014 +0200 +++ b/hotspot/src/share/vm/runtime/thread.hpp Thu Sep 04 11:21:08 2014 +0200 @@ -40,6 +40,7 @@ #include "runtime/safepoint.hpp" #include "runtime/stubRoutines.hpp" #include "runtime/threadLocalStorage.hpp" +#include "runtime/thread_ext.hpp" #include "runtime/unhandledOops.hpp" #include "utilities/macros.hpp" @@ -256,6 +257,8 @@ TRACE_DATA _trace_data; // Thread-local data for tracing + ThreadExt _ext; + int _vm_operation_started_count; // VM_Operation support int _vm_operation_completed_count; // VM_Operation support @@ -409,6 +412,9 @@ TRACE_DATA* trace_data() { return &_trace_data; } + const ThreadExt& ext() const { return _ext; } + ThreadExt& ext() { return _ext; } + // VM operation support int vm_operation_ticket() { return ++_vm_operation_started_count; } int vm_operation_completed_count() { return _vm_operation_completed_count; } @@ -978,6 +984,7 @@ // not specified, use the priority of the thread object. Threads_lock // must be held while this function is called. void prepare(jobject jni_thread, ThreadPriority prio=NoPriority); + void prepare_ext(); void set_saved_exception_pc(address pc) { _saved_exception_pc = pc; } address saved_exception_pc() { return _saved_exception_pc; } @@ -1910,6 +1917,8 @@ // Deoptimizes all frames tied to marked nmethods static void deoptimized_wrt_marked_nmethods(); + static JavaThread* find_java_thread_from_java_tid(jlong java_tid); + }; diff -r fa1e0d1c960f -r 41332d860d6a hotspot/src/share/vm/runtime/thread_ext.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/runtime/thread_ext.cpp Thu Sep 04 11:21:08 2014 +0200 @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "runtime/thread.hpp" +#include "runtime/thread_ext.hpp" + +void JavaThread::prepare_ext() { +} + diff -r fa1e0d1c960f -r 41332d860d6a hotspot/src/share/vm/runtime/thread_ext.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/src/share/vm/runtime/thread_ext.hpp Thu Sep 04 11:21:08 2014 +0200 @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_RUNTIME_THREAD_EXT_HPP +#define SHARE_VM_RUNTIME_THREAD_EXT_HPP + +#include "memory/allocation.hpp" + +class ThreadExt VALUE_OBJ_CLASS_SPEC { +public: + void print_on(outputStream* st) const {}; +}; + +#endif // SHARE_VM_RUNTIME_THREAD_EXT_HPP diff -r fa1e0d1c960f -r 41332d860d6a hotspot/src/share/vm/services/management.cpp --- a/hotspot/src/share/vm/services/management.cpp Mon Sep 22 16:22:21 2014 +0200 +++ b/hotspot/src/share/vm/services/management.cpp Thu Sep 04 11:21:08 2014 +0200 @@ -392,23 +392,6 @@ return (instanceOop) element(); } -// Helper functions -static JavaThread* find_java_thread_from_id(jlong thread_id) { - assert(Threads_lock->owned_by_self(), "Must hold Threads_lock"); - - JavaThread* java_thread = NULL; - // Sequential search for now. Need to do better optimization later. - for (JavaThread* thread = Threads::first(); thread != NULL; thread = thread->next()) { - oop tobj = thread->threadObj(); - if (!thread->is_exiting() && - tobj != NULL && - thread_id == java_lang_Thread::thread_id(tobj)) { - java_thread = thread; - break; - } - } - return java_thread; -} static GCMemoryManager* get_gc_memory_manager_from_jobject(jobject mgr, TRAPS) { if (mgr == NULL) { @@ -445,6 +428,8 @@ return MemoryService::get_memory_pool(ph); } +#endif // INCLUDE_MANAGEMENT + static void validate_thread_id_array(typeArrayHandle ids_ah, TRAPS) { int num_threads = ids_ah->length(); @@ -460,6 +445,8 @@ } } +#if INCLUDE_MANAGEMENT + static void validate_thread_info_array(objArrayHandle infoArray_h, TRAPS) { // check if the element of infoArray is of type ThreadInfo class Klass* threadinfo_klass = Management::java_lang_management_ThreadInfo_klass(CHECK); @@ -823,45 +810,6 @@ return prev; JVM_END -// Gets an array containing the amount of memory allocated on the Java -// heap for a set of threads (in bytes). Each element of the array is -// the amount of memory allocated for the thread ID specified in the -// corresponding entry in the given array of thread IDs; or -1 if the -// thread does not exist or has terminated. -JVM_ENTRY(void, jmm_GetThreadAllocatedMemory(JNIEnv *env, jlongArray ids, - jlongArray sizeArray)) - // Check if threads is null - if (ids == NULL || sizeArray == NULL) { - THROW(vmSymbols::java_lang_NullPointerException()); - } - - ResourceMark rm(THREAD); - typeArrayOop ta = typeArrayOop(JNIHandles::resolve_non_null(ids)); - typeArrayHandle ids_ah(THREAD, ta); - - typeArrayOop sa = typeArrayOop(JNIHandles::resolve_non_null(sizeArray)); - typeArrayHandle sizeArray_h(THREAD, sa); - - // validate the thread id array - validate_thread_id_array(ids_ah, CHECK); - - // sizeArray must be of the same length as the given array of thread IDs - int num_threads = ids_ah->length(); - if (num_threads != sizeArray_h->length()) { - THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), - "The length of the given long array does not match the length of " - "the given array of thread IDs"); - } - - MutexLockerEx ml(Threads_lock); - for (int i = 0; i < num_threads; i++) { - JavaThread* java_thread = find_java_thread_from_id(ids_ah->long_at(i)); - if (java_thread != NULL) { - sizeArray_h->long_at_put(i, java_thread->cooked_allocated_bytes()); - } - } -JVM_END - // Returns a java/lang/management/MemoryUsage object representing // the memory usage for the heap or non-heap memory. JVM_ENTRY(jobject, jmm_GetMemoryUsage(JNIEnv* env, jboolean heap)) @@ -1167,7 +1115,7 @@ MutexLockerEx ml(Threads_lock); for (int i = 0; i < num_threads; i++) { jlong tid = ids_ah->long_at(i); - JavaThread* jt = find_java_thread_from_id(tid); + JavaThread* jt = Threads::find_java_thread_from_java_tid(tid); oop thread_obj = (jt != NULL ? jt->threadObj() : (oop)NULL); instanceHandle threadObj_h(THREAD, (instanceOop) thread_obj); thread_handle_array->append(threadObj_h); @@ -1244,7 +1192,7 @@ MutexLockerEx ml(Threads_lock); for (int i = 0; i < num_threads; i++) { jlong tid = ids_ah->long_at(i); - JavaThread* jt = find_java_thread_from_id(tid); + JavaThread* jt = Threads::find_java_thread_from_java_tid(tid); ThreadSnapshot* ts; if (jt == NULL) { // if the thread does not exist or now it is terminated, @@ -1488,7 +1436,7 @@ } } else { // reset contention statistics for a given thread - JavaThread* java_thread = find_java_thread_from_id(tid); + JavaThread* java_thread = Threads::find_java_thread_from_java_tid(tid); if (java_thread == NULL) { return false; } @@ -1557,7 +1505,7 @@ return os::current_thread_cpu_time(); } else { MutexLockerEx ml(Threads_lock); - java_thread = find_java_thread_from_id(thread_id); + java_thread = Threads::find_java_thread_from_java_tid(thread_id); if (java_thread != NULL) { return os::thread_cpu_time((Thread*) java_thread); } @@ -1565,78 +1513,6 @@ return -1; JVM_END -// Returns the CPU time consumed by a given thread (in nanoseconds). -// If thread_id == 0, CPU time for the current thread is returned. -// If user_sys_cpu_time = true, user level and system CPU time of -// a given thread is returned; otherwise, only user level CPU time -// is returned. -JVM_ENTRY(jlong, jmm_GetThreadCpuTimeWithKind(JNIEnv *env, jlong thread_id, jboolean user_sys_cpu_time)) - if (!os::is_thread_cpu_time_supported()) { - return -1; - } - - if (thread_id < 0) { - THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), - "Invalid thread ID", -1); - } - - JavaThread* java_thread = NULL; - if (thread_id == 0) { - // current thread - return os::current_thread_cpu_time(user_sys_cpu_time != 0); - } else { - MutexLockerEx ml(Threads_lock); - java_thread = find_java_thread_from_id(thread_id); - if (java_thread != NULL) { - return os::thread_cpu_time((Thread*) java_thread, user_sys_cpu_time != 0); - } - } - return -1; -JVM_END - -// Gets an array containing the CPU times consumed by a set of threads -// (in nanoseconds). Each element of the array is the CPU time for the -// thread ID specified in the corresponding entry in the given array -// of thread IDs; or -1 if the thread does not exist or has terminated. -// If user_sys_cpu_time = true, the sum of user level and system CPU time -// for the given thread is returned; otherwise, only user level CPU time -// is returned. -JVM_ENTRY(void, jmm_GetThreadCpuTimesWithKind(JNIEnv *env, jlongArray ids, - jlongArray timeArray, - jboolean user_sys_cpu_time)) - // Check if threads is null - if (ids == NULL || timeArray == NULL) { - THROW(vmSymbols::java_lang_NullPointerException()); - } - - ResourceMark rm(THREAD); - typeArrayOop ta = typeArrayOop(JNIHandles::resolve_non_null(ids)); - typeArrayHandle ids_ah(THREAD, ta); - - typeArrayOop tia = typeArrayOop(JNIHandles::resolve_non_null(timeArray)); - typeArrayHandle timeArray_h(THREAD, tia); - - // validate the thread id array - validate_thread_id_array(ids_ah, CHECK); - - // timeArray must be of the same length as the given array of thread IDs - int num_threads = ids_ah->length(); - if (num_threads != timeArray_h->length()) { - THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), - "The length of the given long array does not match the length of " - "the given array of thread IDs"); - } - - MutexLockerEx ml(Threads_lock); - for (int i = 0; i < num_threads; i++) { - JavaThread* java_thread = find_java_thread_from_id(ids_ah->long_at(i)); - if (java_thread != NULL) { - timeArray_h->long_at_put(i, os::thread_cpu_time((Thread*)java_thread, - user_sys_cpu_time != 0)); - } - } -JVM_END - // Returns a String array of all VM global flag names JVM_ENTRY(jobjectArray, jmm_GetVMGlobalNames(JNIEnv *env)) // last flag entry is always NULL, so subtract 1 @@ -2331,7 +2207,122 @@ return (jlong)(((double)ticks / (double)os::elapsed_frequency()) * (double)1000.0); } +#endif // INCLUDE_MANAGEMENT +// Gets an array containing the amount of memory allocated on the Java +// heap for a set of threads (in bytes). Each element of the array is +// the amount of memory allocated for the thread ID specified in the +// corresponding entry in the given array of thread IDs; or -1 if the +// thread does not exist or has terminated. +JVM_ENTRY(void, jmm_GetThreadAllocatedMemory(JNIEnv *env, jlongArray ids, + jlongArray sizeArray)) + // Check if threads is null + if (ids == NULL || sizeArray == NULL) { + THROW(vmSymbols::java_lang_NullPointerException()); + } + + ResourceMark rm(THREAD); + typeArrayOop ta = typeArrayOop(JNIHandles::resolve_non_null(ids)); + typeArrayHandle ids_ah(THREAD, ta); + + typeArrayOop sa = typeArrayOop(JNIHandles::resolve_non_null(sizeArray)); + typeArrayHandle sizeArray_h(THREAD, sa); + + // validate the thread id array + validate_thread_id_array(ids_ah, CHECK); + + // sizeArray must be of the same length as the given array of thread IDs + int num_threads = ids_ah->length(); + if (num_threads != sizeArray_h->length()) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "The length of the given long array does not match the length of " + "the given array of thread IDs"); + } + + MutexLockerEx ml(Threads_lock); + for (int i = 0; i < num_threads; i++) { + JavaThread* java_thread = Threads::find_java_thread_from_java_tid(ids_ah->long_at(i)); + if (java_thread != NULL) { + sizeArray_h->long_at_put(i, java_thread->cooked_allocated_bytes()); + } + } +JVM_END + +// Returns the CPU time consumed by a given thread (in nanoseconds). +// If thread_id == 0, CPU time for the current thread is returned. +// If user_sys_cpu_time = true, user level and system CPU time of +// a given thread is returned; otherwise, only user level CPU time +// is returned. +JVM_ENTRY(jlong, jmm_GetThreadCpuTimeWithKind(JNIEnv *env, jlong thread_id, jboolean user_sys_cpu_time)) + if (!os::is_thread_cpu_time_supported()) { + return -1; + } + + if (thread_id < 0) { + THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), + "Invalid thread ID", -1); + } + + JavaThread* java_thread = NULL; + if (thread_id == 0) { + // current thread + return os::current_thread_cpu_time(user_sys_cpu_time != 0); + } else { + MutexLockerEx ml(Threads_lock); + java_thread = Threads::find_java_thread_from_java_tid(thread_id); + if (java_thread != NULL) { + return os::thread_cpu_time((Thread*) java_thread, user_sys_cpu_time != 0); + } + } + return -1; +JVM_END + +// Gets an array containing the CPU times consumed by a set of threads +// (in nanoseconds). Each element of the array is the CPU time for the +// thread ID specified in the corresponding entry in the given array +// of thread IDs; or -1 if the thread does not exist or has terminated. +// If user_sys_cpu_time = true, the sum of user level and system CPU time +// for the given thread is returned; otherwise, only user level CPU time +// is returned. +JVM_ENTRY(void, jmm_GetThreadCpuTimesWithKind(JNIEnv *env, jlongArray ids, + jlongArray timeArray, + jboolean user_sys_cpu_time)) + // Check if threads is null + if (ids == NULL || timeArray == NULL) { + THROW(vmSymbols::java_lang_NullPointerException()); + } + + ResourceMark rm(THREAD); + typeArrayOop ta = typeArrayOop(JNIHandles::resolve_non_null(ids)); + typeArrayHandle ids_ah(THREAD, ta); + + typeArrayOop tia = typeArrayOop(JNIHandles::resolve_non_null(timeArray)); + typeArrayHandle timeArray_h(THREAD, tia); + + // validate the thread id array + validate_thread_id_array(ids_ah, CHECK); + + // timeArray must be of the same length as the given array of thread IDs + int num_threads = ids_ah->length(); + if (num_threads != timeArray_h->length()) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "The length of the given long array does not match the length of " + "the given array of thread IDs"); + } + + MutexLockerEx ml(Threads_lock); + for (int i = 0; i < num_threads; i++) { + JavaThread* java_thread = Threads::find_java_thread_from_java_tid(ids_ah->long_at(i)); + if (java_thread != NULL) { + timeArray_h->long_at_put(i, os::thread_cpu_time((Thread*)java_thread, + user_sys_cpu_time != 0)); + } + } +JVM_END + + + +#if INCLUDE_MANAGEMENT const struct jmmInterface_1_ jmm_interface = { NULL, NULL,