< prev index next >

src/hotspot/share/prims/jvmtiEnv.cpp

Print this page
rev 47287 : Port 09.17.Thread_SMR_logging_update from JDK9 to JDK10
rev 47288 : sspitsyn, dcubed, eosterlund CR - minor changes prior to OpenJDK review.
rev 47289 : eosterlund, stefank CR - refactor code into threadSMR.cpp and threadSMR.hpp

@@ -60,10 +60,11 @@
 #include "runtime/jfieldIDWorkaround.hpp"
 #include "runtime/osThread.hpp"
 #include "runtime/reflectionUtils.hpp"
 #include "runtime/signature.hpp"
 #include "runtime/thread.inline.hpp"
+#include "runtime/threadSMR.hpp"
 #include "runtime/timerTrace.hpp"
 #include "runtime/vframe.hpp"
 #include "runtime/vmThread.hpp"
 #include "services/threadService.hpp"
 #include "utilities/exceptions.hpp"

@@ -160,31 +161,26 @@
   if (thread == NULL) {
     JvmtiThreadState* state = current_thread->jvmti_thread_state();
     *data_ptr = (state == NULL) ? NULL :
       state->env_thread_state(this)->get_agent_thread_local_storage_data();
   } else {
-
     // jvmti_GetThreadLocalStorage is "in native" and doesn't transition
     // the thread to _thread_in_vm. However, when the TLS for a thread
     // other than the current thread is required we need to transition
     // from native so as to resolve the jthread.
 
     ThreadInVMfromNative __tiv(current_thread);
     VM_ENTRY_BASE(jvmtiError, JvmtiEnv::GetThreadLocalStorage , current_thread)
     debug_only(VMNativeEntryWrapper __vew;)
 
-    oop thread_oop = JNIHandles::resolve_external_guard(thread);
-    if (thread_oop == NULL) {
-      return JVMTI_ERROR_INVALID_THREAD;
+    JavaThread* java_thread = NULL;
+    ThreadsListHandle tlh(current_thread);
+    jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), thread, &java_thread, NULL);
+    if (err != JVMTI_ERROR_NONE) {
+      return err;
     }
-    if (!thread_oop->is_a(SystemDictionary::Thread_klass())) {
-      return JVMTI_ERROR_INVALID_THREAD;
-    }
-    JavaThread* java_thread = java_lang_Thread::thread(thread_oop);
-    if (java_thread == NULL) {
-      return JVMTI_ERROR_THREAD_NOT_ALIVE;
-    }
+
     JvmtiThreadState* state = java_thread->jvmti_thread_state();
     *data_ptr = (state == NULL) ? NULL :
       state->env_thread_state(this)->get_agent_thread_local_storage_data();
   }
   return JVMTI_ERROR_NONE;

@@ -516,32 +512,49 @@
 
 
 // event_thread - NULL is a valid value, must be checked
 jvmtiError
 JvmtiEnv::SetEventNotificationMode(jvmtiEventMode mode, jvmtiEvent event_type, jthread event_thread,   ...) {
-  JavaThread* java_thread = NULL;
-  if (event_thread != NULL) {
-    oop thread_oop = JNIHandles::resolve_external_guard(event_thread);
-    if (thread_oop == NULL) {
-      return JVMTI_ERROR_INVALID_THREAD;
+  if (event_thread == NULL) {
+    // Can be called at Agent_OnLoad() time with event_thread == NULL
+    // when Thread::current() does not work yet so we cannot create a
+    // ThreadsListHandle that is common to both thread-specific and
+    // global code paths.
+
+    // event_type must be valid
+    if (!JvmtiEventController::is_valid_event_type(event_type)) {
+      return JVMTI_ERROR_INVALID_EVENT_TYPE;
     }
-    if (!thread_oop->is_a(SystemDictionary::Thread_klass())) {
-      return JVMTI_ERROR_INVALID_THREAD;
+
+    bool enabled = (mode == JVMTI_ENABLE);
+
+    // assure that needed capabilities are present
+    if (enabled && !JvmtiUtil::has_event_capability(event_type, get_capabilities())) {
+      return JVMTI_ERROR_MUST_POSSESS_CAPABILITY;
     }
-    java_thread = java_lang_Thread::thread(thread_oop);
-    if (java_thread == NULL) {
-      return JVMTI_ERROR_THREAD_NOT_ALIVE;
+
+    if (event_type == JVMTI_EVENT_CLASS_FILE_LOAD_HOOK && enabled) {
+      record_class_file_load_hook_enabled();
     }
+    JvmtiEventController::set_user_enabled(this, (JavaThread*) NULL, event_type, enabled);
+  } else {
+    // We have a specified event_thread.
+
+    JavaThread* java_thread = NULL;
+    ThreadsListHandle tlh;
+    jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), event_thread, &java_thread, NULL);
+    if (err != JVMTI_ERROR_NONE) {
+      return err;
   }
 
   // event_type must be valid
   if (!JvmtiEventController::is_valid_event_type(event_type)) {
     return JVMTI_ERROR_INVALID_EVENT_TYPE;
   }
 
   // global events cannot be controlled at thread level.
-  if (java_thread != NULL && JvmtiEventController::is_global_event(event_type)) {
+    if (JvmtiEventController::is_global_event(event_type)) {
     return JVMTI_ERROR_ILLEGAL_ARGUMENT;
   }
 
   bool enabled = (mode == JVMTI_ENABLE);
 

@@ -552,10 +565,11 @@
 
   if (event_type == JVMTI_EVENT_CLASS_FILE_LOAD_HOOK && enabled) {
     record_class_file_load_hook_enabled();
   }
   JvmtiEventController::set_user_enabled(this, java_thread, event_type, enabled);
+  }
 
   return JVMTI_ERROR_NONE;
 } /* end SetEventNotificationMode */
 
   //

@@ -815,39 +829,49 @@
 // Threads_lock NOT held
 // thread - NOT pre-checked
 // thread_state_ptr - pre-checked for NULL
 jvmtiError
 JvmtiEnv::GetThreadState(jthread thread, jint* thread_state_ptr) {
-  jint state;
-  oop thread_oop;
-  JavaThread* thr;
+  JavaThread* current_thread = JavaThread::current();
+  JavaThread* java_thread = NULL;
+  oop thread_oop = NULL;
+  ThreadsListHandle tlh(current_thread);
 
   if (thread == NULL) {
-    thread_oop = JavaThread::current()->threadObj();
-  } else {
-    thread_oop = JNIHandles::resolve_external_guard(thread);
-  }
+    java_thread = current_thread;
+    thread_oop = java_thread->threadObj();
 
   if (thread_oop == NULL || !thread_oop->is_a(SystemDictionary::Thread_klass())) {
     return JVMTI_ERROR_INVALID_THREAD;
   }
+  } else {
+    jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), thread, &java_thread, &thread_oop);
+    if (err != JVMTI_ERROR_NONE) {
+      // We got an error code so we don't have a JavaThread *, but
+      // only return an error from here if we didn't get a valid
+      // thread_oop.
+      if (thread_oop == NULL) {
+        return err;
+      }
+      // We have a valid thread_oop so we can return some thread state.
+    }
+  }
 
   // get most state bits
-  state = (jint)java_lang_Thread::get_thread_status(thread_oop);
+  jint state = (jint)java_lang_Thread::get_thread_status(thread_oop);
 
-  // add more state bits
-  thr = java_lang_Thread::thread(thread_oop);
-  if (thr != NULL) {
-    JavaThreadState jts = thr->thread_state();
+  if (java_thread != NULL) {
+    // We have a JavaThread* so add more state bits.
+    JavaThreadState jts = java_thread->thread_state();
 
-    if (thr->is_being_ext_suspended()) {
+    if (java_thread->is_being_ext_suspended()) {
       state |= JVMTI_THREAD_STATE_SUSPENDED;
     }
     if (jts == _thread_in_native) {
       state |= JVMTI_THREAD_STATE_IN_NATIVE;
     }
-    OSThread* osThread = thr->osthread();
+    OSThread* osThread = java_thread->osthread();
     if (osThread != NULL && osThread->interrupted()) {
       state |= JVMTI_THREAD_STATE_INTERRUPTED;
     }
   }
 

@@ -889,11 +913,10 @@
 
   for (int i=0; i < nthreads; i++) {
     thread_objs[i] = Handle(tle.get_threadObj(i));
   }
 
-  // have to make global handles outside of Threads_lock
   jthread *jthreads  = new_jthreadArray(nthreads, thread_objs);
   NULL_CHECK(jthreads, JVMTI_ERROR_OUT_OF_MEMORY);
 
   *threads_ptr = jthreads;
   return JVMTI_ERROR_NONE;

@@ -933,25 +956,18 @@
 // request_list - pre-checked for NULL
 // results - pre-checked for NULL
 jvmtiError
 JvmtiEnv::SuspendThreadList(jint request_count, const jthread* request_list, jvmtiError* results) {
   int needSafepoint = 0;  // > 0 if we need a safepoint
+  ThreadsListHandle tlh;
   for (int i = 0; i < request_count; i++) {
-    JavaThread *java_thread = get_JavaThread(request_list[i]);
-    if (java_thread == NULL) {
-      results[i] = JVMTI_ERROR_INVALID_THREAD;
+    JavaThread *java_thread = NULL;
+    jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), request_list[i], &java_thread, NULL);
+    if (err != JVMTI_ERROR_NONE) {
+      results[i] = err;
       continue;
     }
-    // the thread has not yet run or has exited (not on threads list)
-    if (java_thread->threadObj() == NULL) {
-      results[i] = JVMTI_ERROR_THREAD_NOT_ALIVE;
-      continue;
-    }
-    if (java_lang_Thread::thread(java_thread->threadObj()) == NULL) {
-      results[i] = JVMTI_ERROR_THREAD_NOT_ALIVE;
-      continue;
-    }
     // don't allow hidden thread suspend request.
     if (java_thread->is_hidden_from_external_view()) {
       results[i] = JVMTI_ERROR_NONE;  // indicate successful suspend
       continue;
     }

@@ -1016,14 +1032,16 @@
 // request_count - pre-checked to be greater than or equal to 0
 // request_list - pre-checked for NULL
 // results - pre-checked for NULL
 jvmtiError
 JvmtiEnv::ResumeThreadList(jint request_count, const jthread* request_list, jvmtiError* results) {
+  ThreadsListHandle tlh;
   for (int i = 0; i < request_count; i++) {
-    JavaThread *java_thread = get_JavaThread(request_list[i]);
-    if (java_thread == NULL) {
-      results[i] = JVMTI_ERROR_INVALID_THREAD;
+    JavaThread* java_thread = NULL;
+    jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), request_list[i], &java_thread, NULL);
+    if (err != JVMTI_ERROR_NONE) {
+      results[i] = err;
       continue;
     }
     // don't allow hidden thread resume request.
     if (java_thread->is_hidden_from_external_view()) {
       results[i] = JVMTI_ERROR_NONE;  // indicate successful resume

@@ -1037,11 +1055,11 @@
     if (!JvmtiSuspendControl::resume(java_thread)) {
       results[i] = JVMTI_ERROR_INTERNAL;
       continue;
     }
 
-    results[i] = JVMTI_ERROR_NONE;  // indicate successful suspend
+    results[i] = JVMTI_ERROR_NONE;  // indicate successful resume
   }
   // per-thread resume results returned via results parameter
   return JVMTI_ERROR_NONE;
 } /* end ResumeThreadList */
 

@@ -1062,25 +1080,19 @@
 
 // Threads_lock NOT held
 // thread - NOT pre-checked
 jvmtiError
 JvmtiEnv::InterruptThread(jthread thread) {
-  oop thread_oop = JNIHandles::resolve_external_guard(thread);
-  if (thread_oop == NULL || !thread_oop->is_a(SystemDictionary::Thread_klass()))
-    return JVMTI_ERROR_INVALID_THREAD;
-
+  // TODO: this is very similar to JVM_Interrupt(); share code in future
   JavaThread* current_thread  = JavaThread::current();
+  JavaThread* java_thread = NULL;
+  ThreadsListHandle tlh(current_thread);
+  jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), thread, &java_thread, NULL);
+  if (err != JVMTI_ERROR_NONE) {
+    return err;
+  }
 
-  // Todo: this is a duplicate of JVM_Interrupt; share code in future
-  // Ensure that the C++ Thread and OSThread structures aren't freed before we operate
-  MutexLockerEx ml(current_thread->threadObj() == thread_oop ? NULL : Threads_lock);
-  // We need to re-resolve the java_thread, since a GC might have happened during the
-  // acquire of the lock
-
-  JavaThread* java_thread = java_lang_Thread::thread(JNIHandles::resolve_external_guard(thread));
-  NULL_CHECK(java_thread, JVMTI_ERROR_THREAD_NOT_ALIVE);
-
   Thread::interrupt(java_thread);
 
   return JVMTI_ERROR_NONE;
 } /* end InterruptThread */
 

@@ -1092,20 +1104,32 @@
 JvmtiEnv::GetThreadInfo(jthread thread, jvmtiThreadInfo* info_ptr) {
   ResourceMark rm;
   HandleMark hm;
 
   JavaThread* current_thread = JavaThread::current();
+  ThreadsListHandle tlh(current_thread);
 
   // if thread is NULL the current thread is used
-  oop thread_oop;
+  oop thread_oop = NULL;
   if (thread == NULL) {
     thread_oop = current_thread->threadObj();
+    if (thread_oop == NULL || !thread_oop->is_a(SystemDictionary::Thread_klass())) {
+      return JVMTI_ERROR_INVALID_THREAD;
+    }
   } else {
-    thread_oop = JNIHandles::resolve_external_guard(thread);
+    JavaThread* java_thread = NULL;
+    jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), thread, &java_thread, &thread_oop);
+    if (err != JVMTI_ERROR_NONE) {
+      // We got an error code so we don't have a JavaThread *, but
+      // only return an error from here if we didn't get a valid
+      // thread_oop.
+      if (thread_oop == NULL) {
+        return err;
   }
-  if (thread_oop == NULL || !thread_oop->is_a(SystemDictionary::Thread_klass()))
-    return JVMTI_ERROR_INVALID_THREAD;
+      // We have a valid thread_oop so we can return some thread info.
+    }
+  }
 
   Handle thread_obj(current_thread, thread_oop);
   Handle name;
   ThreadPriority priority;
   Handle     thread_group;

@@ -1270,31 +1294,47 @@
 // thread - NOT pre-checked
 // proc - pre-checked for NULL
 // arg - NULL is a valid value, must be checked
 jvmtiError
 JvmtiEnv::RunAgentThread(jthread thread, jvmtiStartFunction proc, const void* arg, jint priority) {
-  oop thread_oop = JNIHandles::resolve_external_guard(thread);
-  if (thread_oop == NULL || !thread_oop->is_a(SystemDictionary::Thread_klass())) {
+  JavaThread* current_thread = JavaThread::current();
+
+  JavaThread* java_thread = NULL;
+  oop thread_oop = NULL;
+  ThreadsListHandle tlh(current_thread);
+  jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), thread, &java_thread, &thread_oop);
+  if (err != JVMTI_ERROR_NONE) {
+    // We got an error code so we don't have a JavaThread *, but
+    // only return an error from here if we didn't get a valid
+    // thread_oop.
+    if (thread_oop == NULL) {
+      return err;
+    }
+    // We have a valid thread_oop.
+  }
+
+  if (java_thread != NULL) {
+    // 'thread' refers to an existing JavaThread.
     return JVMTI_ERROR_INVALID_THREAD;
   }
+
   if (priority < JVMTI_THREAD_MIN_PRIORITY || priority > JVMTI_THREAD_MAX_PRIORITY) {
     return JVMTI_ERROR_INVALID_PRIORITY;
   }
 
-  //Thread-self
-  JavaThread* current_thread = JavaThread::current();
-
   Handle thread_hndl(current_thread, thread_oop);
   {
     MutexLocker mu(Threads_lock); // grab Threads_lock
 
     JvmtiAgentThread *new_thread = new JvmtiAgentThread(this, proc, arg);
 
     // At this point it may be possible that no osthread was created for the
     // JavaThread due to lack of memory.
     if (new_thread == NULL || new_thread->osthread() == NULL) {
-      if (new_thread) delete new_thread;
+      if (new_thread != NULL) {
+        new_thread->smr_delete();
+      }
       return JVMTI_ERROR_OUT_OF_MEMORY;
     }
 
     java_lang_Thread::set_thread(thread_hndl(), new_thread);
     java_lang_Thread::set_priority(thread_hndl(), (ThreadPriority)priority);

@@ -1392,40 +1432,57 @@
   Handle *group_objs  = NULL;
   int nthreads = 0;
   int ngroups = 0;
   int hidden_threads = 0;
 
-  ResourceMark rm;
-  HandleMark hm;
+  ResourceMark rm(current_thread);
+  HandleMark hm(current_thread);
 
   Handle group_hdl(current_thread, group_obj);
 
-  { MutexLocker mu(Threads_lock);
+  { // Cannot allow thread or group counts to change.
+    MutexLocker mu(Threads_lock);
 
     nthreads = java_lang_ThreadGroup::nthreads(group_hdl());
     ngroups  = java_lang_ThreadGroup::ngroups(group_hdl());
 
     if (nthreads > 0) {
+      ThreadsListHandle tlh(current_thread);
       objArrayOop threads = java_lang_ThreadGroup::threads(group_hdl());
       assert(nthreads <= threads->length(), "too many threads");
       thread_objs = NEW_RESOURCE_ARRAY(Handle,nthreads);
       for (int i=0, j=0; i<nthreads; i++) {
         oop thread_obj = threads->obj_at(i);
         assert(thread_obj != NULL, "thread_obj is NULL");
-        JavaThread *javathread = java_lang_Thread::thread(thread_obj);
+        JavaThread *java_thread = NULL;
+        jvmtiError err = JvmtiExport::cv_oop_to_JavaThread(tlh.list(), thread_obj, &java_thread);
+        if (err == JVMTI_ERROR_NONE) {
+          // Have a valid JavaThread*.
+          if (java_thread->is_hidden_from_external_view()) {
         // Filter out hidden java threads.
-        if (javathread != NULL && javathread->is_hidden_from_external_view()) {
           hidden_threads++;
           continue;
         }
+        } else {
+          // We couldn't convert thread_obj into a JavaThread*.
+          if (err == JVMTI_ERROR_INVALID_THREAD) {
+            // The thread_obj does not refer to a java.lang.Thread object
+            // so skip it.
+            hidden_threads++;
+            continue;
+          }
+          // We have a valid thread_obj, but no JavaThread*; the caller
+          // can still have limited use for the thread_obj.
+        }
         thread_objs[j++] = Handle(current_thread, thread_obj);
       }
       nthreads -= hidden_threads;
-    }
+    } // ThreadsListHandle is destroyed here.
+
     if (ngroups > 0) {
       objArrayOop groups = java_lang_ThreadGroup::groups(group_hdl());
-      assert(ngroups <= groups->length(), "too many threads");
+      assert(ngroups <= groups->length(), "too many groups");
       group_objs = NEW_RESOURCE_ARRAY(Handle,ngroups);
       for (int i=0; i<ngroups; i++) {
         oop group_obj = groups->obj_at(i);
         assert(group_obj != NULL, "group_obj != NULL");
         group_objs[i] = Handle(current_thread, group_obj);

@@ -1554,11 +1611,11 @@
   if (state == NULL) {
     return JVMTI_ERROR_THREAD_NOT_ALIVE;
   }
 
   // Check if java_thread is fully suspended
-  if (!is_thread_fully_suspended(java_thread, true /* wait for suspend completion */, &debug_bits)) {
+  if (!java_thread->is_thread_fully_suspended(true /* wait for suspend completion */, &debug_bits)) {
     return JVMTI_ERROR_THREAD_NOT_SUSPENDED;
   }
   // Check to see if a PopFrame was already in progress
   if (java_thread->popframe_condition() != JavaThread::popframe_inactive) {
     // Probably possible for JVMTI clients to trigger this, but the

@@ -1684,11 +1741,11 @@
   JvmtiThreadState *state = JvmtiThreadState::state_for(java_thread);
   if (state == NULL) {
     return JVMTI_ERROR_THREAD_NOT_ALIVE;
   }
 
-  if (!JvmtiEnv::is_thread_fully_suspended(java_thread, true, &debug_bits)) {
+  if (!java_thread->is_thread_fully_suspended(true, &debug_bits)) {
       return JVMTI_ERROR_THREAD_NOT_SUSPENDED;
   }
 
   if (TraceJVMTICalls) {
     JvmtiSuspendControl::print();
< prev index next >