--- a/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp Fri May 17 15:53:21 2019 +0200
+++ b/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp Fri May 17 16:02:27 2019 +0200
@@ -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<jweak>* 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<jweak>(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);
+ }
+}