< prev index next >

src/hotspot/share/services/threadService.cpp

Print this page
*** 1175,24 ***
    int _frame_count; // length of _methods and _bcis arrays
    GrowableArray<Method*>* _methods;
    GrowableArray<int>* _bcis;
    JavaThreadStatus _thread_status;
    OopHandle _thread_name;
    GrowableArray<OwnedLock>* _locks;
    Blocker _blocker;
  
    GetThreadSnapshotHandshakeClosure(Handle thread_h, JavaThread* java_thread):
      HandshakeClosure("GetThreadSnapshotHandshakeClosure"),
      _thread_h(thread_h), _java_thread(java_thread),
      _frame_count(0), _methods(nullptr), _bcis(nullptr),
!     _thread_status(), _thread_name(nullptr),
!     _locks(nullptr), _blocker() {
    }
    virtual ~GetThreadSnapshotHandshakeClosure() {
      delete _methods;
      delete _bcis;
      _thread_name.release(oop_storage());
      if (_locks != nullptr) {
        for (int i = 0; i < _locks->length(); i++) {
          _locks->at(i)._obj.release(oop_storage());
        }
        delete _locks;
--- 1175,28 ---
    int _frame_count; // length of _methods and _bcis arrays
    GrowableArray<Method*>* _methods;
    GrowableArray<int>* _bcis;
    JavaThreadStatus _thread_status;
    OopHandle _thread_name;
+   OopHandle _carrier_thread;
    GrowableArray<OwnedLock>* _locks;
    Blocker _blocker;
+   bool _completed;
  
    GetThreadSnapshotHandshakeClosure(Handle thread_h, JavaThread* java_thread):
      HandshakeClosure("GetThreadSnapshotHandshakeClosure"),
      _thread_h(thread_h), _java_thread(java_thread),
      _frame_count(0), _methods(nullptr), _bcis(nullptr),
!     _thread_status(), _thread_name(nullptr), _carrier_thread(nullptr),
!     _locks(nullptr), _blocker(),
+     _completed(false) {
    }
    virtual ~GetThreadSnapshotHandshakeClosure() {
      delete _methods;
      delete _bcis;
      _thread_name.release(oop_storage());
+     _carrier_thread.release(oop_storage());
      if (_locks != nullptr) {
        for (int i = 0; i < _locks->length(); i++) {
          _locks->at(i)._obj.release(oop_storage());
        }
        delete _locks;

*** 1272,24 ***
  public:
    void do_thread(Thread* th) override {
      Thread* current = Thread::current();
  
      bool is_virtual = java_lang_VirtualThread::is_instance(_thread_h());
!     if (_java_thread != nullptr) {
!       if (is_virtual) {
!         // mounted vthread, use carrier thread state
!         oop carrier_thread = java_lang_VirtualThread::carrier_thread(_thread_h());
!         assert(carrier_thread != nullptr, "should only get here for a mounted vthread");
!         _thread_status = java_lang_Thread::get_thread_status(carrier_thread);
        } else {
!         _thread_status = java_lang_Thread::get_thread_status(_thread_h());
        }
      } else {
!       // unmounted vthread
-       int vt_state = java_lang_VirtualThread::state(_thread_h());
-       _thread_status = java_lang_VirtualThread::map_state_to_thread_status(vt_state);
      }
      _thread_name = OopHandle(oop_storage(), java_lang_Thread::name(_thread_h()));
  
      if (_java_thread != nullptr && !_java_thread->has_last_Java_frame()) {
        // stack trace is empty
        return;
--- 1276,37 ---
  public:
    void do_thread(Thread* th) override {
      Thread* current = Thread::current();
  
      bool is_virtual = java_lang_VirtualThread::is_instance(_thread_h());
! 
!     // For a mounted virtual thread then we must check that we are in a handshake with
!     // the JavaThread that has the virtual thread's continuation mounted.
!     if (is_virtual && _java_thread != nullptr) {
!       const ContinuationEntry* ce = _java_thread->vthread_continuation();
!       if (ce == nullptr || ce->cont_oop(_java_thread) != java_lang_VirtualThread::continuation(_thread_h())) {
+         return; // continuation not mounted
+       }
+       assert(_java_thread->vthread() == _thread_h(), "Wrong Thread identity");
+     }
+ 
+     // thread status, and carrier if mounted
+     if (is_virtual) {
+       if (_java_thread != nullptr) {
+         // use carrier status when mounted
+         _thread_status = java_lang_Thread::get_thread_status(_java_thread->threadObj());
+         _carrier_thread = OopHandle(oop_storage(), _java_thread->threadObj());
        } else {
!         // use virtual thread state when unmounted
+         int vt_state = java_lang_VirtualThread::state(_thread_h());
+         assert((vt_state & java_lang_VirtualThread::SUSPENDED) != 0, "Unmounted virtual thread should be suspended");
+         _thread_status = java_lang_VirtualThread::map_state_to_thread_status(vt_state);
        }
      } else {
!       _thread_status = java_lang_Thread::get_thread_status(_thread_h());
      }
+ 
      _thread_name = OopHandle(oop_storage(), java_lang_Thread::name(_thread_h()));
  
      if (_java_thread != nullptr && !_java_thread->has_last_Java_frame()) {
        // stack trace is empty
        return;

*** 1333,10 ***
--- 1350,16 ---
        _bcis->push(vfst.bci());
        total_count++;
      }
  
      _frame_count = total_count;
+ 
+     _completed = true;
+   }
+ 
+   bool is_completed() {
+     return _completed;
    }
  };
  
  class jdk_internal_vm_ThreadLock: AllStatic {
    static bool _inited;

*** 1433,11 ***
  int jdk_internal_vm_ThreadSnapshot::_stackTrace_offset;
  int jdk_internal_vm_ThreadSnapshot::_locks_offset;
  int jdk_internal_vm_ThreadSnapshot::_blockerTypeOrdinal_offset;
  int jdk_internal_vm_ThreadSnapshot::_blockerObject_offset;
  
! oop ThreadSnapshotFactory::get_thread_snapshot(jobject jthread, TRAPS) {
    ThreadsListHandle tlh(THREAD);
  
    ResourceMark rm(THREAD);
    HandleMark   hm(THREAD);
  
--- 1456,11 ---
  int jdk_internal_vm_ThreadSnapshot::_stackTrace_offset;
  int jdk_internal_vm_ThreadSnapshot::_locks_offset;
  int jdk_internal_vm_ThreadSnapshot::_blockerTypeOrdinal_offset;
  int jdk_internal_vm_ThreadSnapshot::_blockerObject_offset;
  
! oop ThreadSnapshotFactory::get_thread_snapshot(jobject jthread, jboolean suspended_by_caller, TRAPS) {
    ThreadsListHandle tlh(THREAD);
  
    ResourceMark rm(THREAD);
    HandleMark   hm(THREAD);
  

*** 1445,68 ***
    oop thread_oop;
    bool has_javathread = tlh.cv_internal_thread_to_JavaThread(jthread, &java_thread, &thread_oop);
    assert((has_javathread && thread_oop != nullptr) || !has_javathread, "Missing Thread oop");
    Handle thread_h(THREAD, thread_oop);
    bool is_virtual = java_lang_VirtualThread::is_instance(thread_h());  // Deals with null
- 
    if (!has_javathread && !is_virtual) {
      return nullptr; // thread terminated so not of interest
    }
  
!   // wrapper to auto delete JvmtiVTMSTransitionDisabler
!   class TransitionDisabler {
!     JvmtiVTMSTransitionDisabler* _transition_disabler;
!   public:
!     TransitionDisabler(): _transition_disabler(nullptr) {}
!     ~TransitionDisabler() {
-       reset();
-     }
-     void init(jobject jthread) {
-       _transition_disabler = new (mtInternal) JvmtiVTMSTransitionDisabler(jthread);
-     }
-     void reset() {
-       if (_transition_disabler != nullptr) {
-         delete _transition_disabler;
-         _transition_disabler = nullptr;
-       }
-     }
-   } transition_disabler;
- 
-   Handle carrier_thread;
-   if (is_virtual) {
-     // 1st need to disable mount/unmount transitions
-     transition_disabler.init(jthread);
- 
-     carrier_thread = Handle(THREAD, java_lang_VirtualThread::carrier_thread(thread_h()));
-     if (carrier_thread != nullptr) {
-       // Note: The java_thread associated with this carrier_thread may not be
-       // protected by the ThreadsListHandle above. There could have been an
-       // unmount and remount after the ThreadsListHandle above was created
-       // and before the JvmtiVTMSTransitionDisabler was created. However, as
-       // we have disabled transitions, if we are mounted on it, then it cannot
-       // terminate and so is safe to handshake with.
-       java_thread = java_lang_Thread::thread(carrier_thread());
-     } else {
-       // We may have previously found a carrier but the virtual thread has unmounted
-       // after that, so clear that previous reference.
-       java_thread = nullptr;
-     }
-   } else {
-     java_thread = java_lang_Thread::thread(thread_h());
    }
  
    // Handshake with target
    GetThreadSnapshotHandshakeClosure cl(thread_h, java_thread);
    if (java_thread == nullptr) {
      // unmounted vthread, execute on the current thread
      cl.do_thread(nullptr);
    } else {
      Handshake::execute(&cl, &tlh, java_thread);
    }
! 
!   // all info is collected, can enable transitions.
!   transition_disabler.reset();
  
    // StackTrace
    InstanceKlass* ste_klass = vmClasses::StackTraceElement_klass();
    assert(ste_klass != nullptr, "must be loaded");
  
--- 1468,33 ---
    oop thread_oop;
    bool has_javathread = tlh.cv_internal_thread_to_JavaThread(jthread, &java_thread, &thread_oop);
    assert((has_javathread && thread_oop != nullptr) || !has_javathread, "Missing Thread oop");
    Handle thread_h(THREAD, thread_oop);
    bool is_virtual = java_lang_VirtualThread::is_instance(thread_h());  // Deals with null
    if (!has_javathread && !is_virtual) {
      return nullptr; // thread terminated so not of interest
    }
  
!   // unmounted virtual thread needs to be suspended by caller
!   if (is_virtual && !has_javathread) {
!    if (suspended_by_caller == JNI_FALSE) {
!      return nullptr;  // called needs to suspend and retry
!    }
!    assert((java_lang_VirtualThread::state(thread_h()) & java_lang_VirtualThread::SUSPENDED) != 0, "Not suspended");
    }
  
    // Handshake with target
    GetThreadSnapshotHandshakeClosure cl(thread_h, java_thread);
    if (java_thread == nullptr) {
      // unmounted vthread, execute on the current thread
      cl.do_thread(nullptr);
    } else {
      Handshake::execute(&cl, &tlh, java_thread);
    }
!   if (!cl.is_completed()) {
!     return nullptr;
!   }
  
    // StackTrace
    InstanceKlass* ste_klass = vmClasses::StackTraceElement_klass();
    assert(ste_klass != nullptr, "must be loaded");
  

*** 1553,11 ***
    }
  
    Handle snapshot = jdk_internal_vm_ThreadSnapshot::allocate(InstanceKlass::cast(snapshot_klass), CHECK_NULL);
    jdk_internal_vm_ThreadSnapshot::set_name(snapshot(), cl._thread_name.resolve());
    jdk_internal_vm_ThreadSnapshot::set_thread_status(snapshot(), (int)cl._thread_status);
!   jdk_internal_vm_ThreadSnapshot::set_carrier_thread(snapshot(), carrier_thread());
    jdk_internal_vm_ThreadSnapshot::set_stack_trace(snapshot(), trace());
    jdk_internal_vm_ThreadSnapshot::set_locks(snapshot(), locks());
    if (!cl._blocker.is_empty()) {
      jdk_internal_vm_ThreadSnapshot::set_blocker(snapshot(), cl._blocker._type, cl._blocker._obj.resolve());
    }
--- 1541,11 ---
    }
  
    Handle snapshot = jdk_internal_vm_ThreadSnapshot::allocate(InstanceKlass::cast(snapshot_klass), CHECK_NULL);
    jdk_internal_vm_ThreadSnapshot::set_name(snapshot(), cl._thread_name.resolve());
    jdk_internal_vm_ThreadSnapshot::set_thread_status(snapshot(), (int)cl._thread_status);
!   jdk_internal_vm_ThreadSnapshot::set_carrier_thread(snapshot(), cl._carrier_thread.resolve());
    jdk_internal_vm_ThreadSnapshot::set_stack_trace(snapshot(), trace());
    jdk_internal_vm_ThreadSnapshot::set_locks(snapshot(), locks());
    if (!cl._blocker.is_empty()) {
      jdk_internal_vm_ThreadSnapshot::set_blocker(snapshot(), cl._blocker._type, cl._blocker._obj.resolve());
    }
< prev index next >