src/hotspot/share/jfr/jni/jfrJavaSupport.cpp
changeset 58863 c16ac7a2eba4
parent 55302 686dedba1d9a
child 59259 127ca611f19b
--- 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<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);
+  }
+}