diff -r 2c3cc4b01880 -r c16ac7a2eba4 src/hotspot/share/jfr/jni/jfrJavaSupport.cpp --- a/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp Wed Oct 30 16:14:56 2019 +0100 +++ b/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp Wed Oct 30 19:43:52 2019 +0100 @@ -23,7 +23,6 @@ */ #include "precompiled.hpp" -#include "jni.h" #include "classfile/javaClasses.inline.hpp" #include "classfile/modules.hpp" #include "classfile/symbolTable.hpp" @@ -42,9 +41,11 @@ #include "runtime/fieldDescriptor.inline.hpp" #include "runtime/java.hpp" #include "runtime/jniHandles.inline.hpp" +#include "runtime/semaphore.inline.hpp" #include "runtime/synchronizer.hpp" #include "runtime/thread.inline.hpp" #include "runtime/threadSMR.hpp" +#include "utilities/growableArray.hpp" #ifdef ASSERT void JfrJavaSupport::check_java_thread_in_vm(Thread* t) { @@ -58,6 +59,12 @@ assert(t->is_Java_thread(), "invariant"); assert(((JavaThread*)t)->thread_state() == _thread_in_native, "invariant"); } + +static void check_new_unstarted_java_thread(Thread* t) { + assert(t != NULL, "invariant"); + assert(t->is_Java_thread(), "invariant"); + assert(((JavaThread*)t)->thread_state() == _thread_new, "invariant"); +} #endif /* @@ -93,6 +100,21 @@ JNIHandles::destroy_global(handle); } +jweak JfrJavaSupport::global_weak_jni_handle(const oop obj, Thread* t) { + DEBUG_ONLY(check_java_thread_in_vm(t)); + HandleMark hm(t); + return JNIHandles::make_weak_global(Handle(t, obj)); +} + +jweak JfrJavaSupport::global_weak_jni_handle(const jobject handle, Thread* t) { + const oop obj = JNIHandles::resolve(handle); + return obj == NULL ? NULL : global_weak_jni_handle(obj, t); +} + +void JfrJavaSupport::destroy_global_weak_jni_handle(jweak handle) { + JNIHandles::destroy_weak_global(handle); +} + oop JfrJavaSupport::resolve_non_null(jobject obj) { return JNIHandles::resolve_non_null(obj); } @@ -603,9 +625,149 @@ return true; } -jlong JfrJavaSupport::jfr_thread_id(jobject target_thread) { +class ThreadExclusionListAccess : public StackObj { + private: + static Semaphore _mutex_semaphore; + public: + ThreadExclusionListAccess() { _mutex_semaphore.wait(); } + ~ThreadExclusionListAccess() { _mutex_semaphore.signal(); } +}; + +Semaphore ThreadExclusionListAccess::_mutex_semaphore(1); +static GrowableArray* exclusion_list = NULL; + +static bool equals(const jweak excluded_thread, Handle target_thread) { + return JfrJavaSupport::resolve_non_null(excluded_thread) == target_thread(); +} + +static int find_exclusion_thread_idx(Handle thread) { + if (exclusion_list != NULL) { + for (int i = 0; i < exclusion_list->length(); ++i) { + if (equals(exclusion_list->at(i), thread)) { + return i; + } + } + } + return -1; +} + +static Handle as_handle(jobject thread) { + return Handle(Thread::current(), JfrJavaSupport::resolve_non_null(thread)); +} + +static bool thread_is_not_excluded(Handle thread) { + return -1 == find_exclusion_thread_idx(thread); +} + +static bool thread_is_not_excluded(jobject thread) { + return thread_is_not_excluded(as_handle(thread)); +} + +static bool is_thread_excluded(jobject thread) { + return !thread_is_not_excluded(thread); +} + +#ifdef ASSERT +static bool is_thread_excluded(Handle thread) { + return !thread_is_not_excluded(thread); +} +#endif // ASSERT + +static int add_thread_to_exclusion_list(jobject thread) { + ThreadExclusionListAccess lock; + if (exclusion_list == NULL) { + exclusion_list = new (ResourceObj::C_HEAP, mtTracing) GrowableArray(10, true, mtTracing); + } + assert(exclusion_list != NULL, "invariant"); + assert(thread_is_not_excluded(thread), "invariant"); + jweak ref = JfrJavaSupport::global_weak_jni_handle(thread, Thread::current()); + const int idx = exclusion_list->append(ref); + assert(is_thread_excluded(thread), "invariant"); + return idx; +} + +static void remove_thread_from_exclusion_list(Handle thread) { + assert(exclusion_list != NULL, "invariant"); + assert(is_thread_excluded(thread), "invariant"); + assert(exclusion_list != NULL, "invariant"); + const int idx = find_exclusion_thread_idx(thread); + assert(idx >= 0, "invariant"); + assert(idx < exclusion_list->length(), "invariant"); + JfrJavaSupport::destroy_global_weak_jni_handle(exclusion_list->at(idx)); + exclusion_list->delete_at(idx); + assert(thread_is_not_excluded(thread), "invariant"); + if (0 == exclusion_list->length()) { + delete exclusion_list; + exclusion_list = NULL; + } +} + +static void remove_thread_from_exclusion_list(jobject thread) { + ThreadExclusionListAccess lock; + remove_thread_from_exclusion_list(as_handle(thread)); +} + +// includes removal +static bool check_exclusion_state_on_thread_start(JavaThread* jt) { + Handle h_obj(jt, jt->threadObj()); + ThreadExclusionListAccess lock; + if (thread_is_not_excluded(h_obj)) { + return false; + } + remove_thread_from_exclusion_list(h_obj); + return true; +} + +jlong JfrJavaSupport::jfr_thread_id(jobject thread) { ThreadsListHandle tlh; JavaThread* native_thread = NULL; - (void)tlh.cv_internal_thread_to_JavaThread(target_thread, &native_thread, NULL); + (void)tlh.cv_internal_thread_to_JavaThread(thread, &native_thread, NULL); return native_thread != NULL ? JFR_THREAD_ID(native_thread) : 0; } + +void JfrJavaSupport::exclude(jobject thread) { + HandleMark hm; + ThreadsListHandle tlh; + JavaThread* native_thread = NULL; + (void)tlh.cv_internal_thread_to_JavaThread(thread, &native_thread, NULL); + if (native_thread != NULL) { + JfrThreadLocal::exclude(native_thread); + } else { + // not started yet, track the thread oop + add_thread_to_exclusion_list(thread); + } +} + +void JfrJavaSupport::include(jobject thread) { + HandleMark hm; + ThreadsListHandle tlh; + JavaThread* native_thread = NULL; + (void)tlh.cv_internal_thread_to_JavaThread(thread, &native_thread, NULL); + if (native_thread != NULL) { + JfrThreadLocal::include(native_thread); + } else { + // not started yet, untrack the thread oop + remove_thread_from_exclusion_list(thread); + } +} + +bool JfrJavaSupport::is_excluded(jobject thread) { + HandleMark hm; + ThreadsListHandle tlh; + JavaThread* native_thread = NULL; + (void)tlh.cv_internal_thread_to_JavaThread(thread, &native_thread, NULL); + return native_thread != NULL ? native_thread->jfr_thread_local()->is_excluded() : is_thread_excluded(thread); +} + +void JfrJavaSupport::on_thread_start(Thread* t) { + assert(t != NULL, "invariant"); + assert(Thread::current() == t, "invariant"); + if (!t->is_Java_thread()) { + return; + } + DEBUG_ONLY(check_new_unstarted_java_thread(t);) + HandleMark hm; + if (check_exclusion_state_on_thread_start((JavaThread*)t)) { + JfrThreadLocal::exclude(t); + } +}