diff --git a/src/hotspot/share/prims/jvmtiExport.cpp b/src/hotspot/share/prims/jvmtiExport.cpp index 10614f445d3d8..b98311b92f69b 100644 --- a/src/hotspot/share/prims/jvmtiExport.cpp +++ b/src/hotspot/share/prims/jvmtiExport.cpp @@ -859,47 +859,6 @@ JvmtiExport::cv_external_thread_to_JavaThread(ThreadsList * t_list, return JVMTI_ERROR_NONE; } -// Convert an oop to a JavaThread found on the specified ThreadsList. -// The ThreadsListHandle in the caller "protects" the returned -// JavaThread *. -// -// On success, *jt_pp is set to the converted JavaThread * and -// JVMTI_ERROR_NONE is returned. On error, returns various -// JVMTI_ERROR_* values. -// -jvmtiError -JvmtiExport::cv_oop_to_JavaThread(ThreadsList * t_list, oop thread_oop, - JavaThread ** jt_pp) { - assert(t_list != nullptr, "must have a ThreadsList"); - assert(thread_oop != nullptr, "must have an oop"); - assert(jt_pp != nullptr, "must have a return JavaThread pointer"); - - if (!thread_oop->is_a(vmClasses::Thread_klass())) { - // The oop is not a java.lang.Thread. - return JVMTI_ERROR_INVALID_THREAD; - } - // Looks like a java.lang.Thread oop at this point. - - JavaThread * java_thread = java_lang_Thread::thread(thread_oop); - if (java_thread == nullptr) { - // The java.lang.Thread does not contain a JavaThread * so it has - // not yet run or it has died. - return JVMTI_ERROR_THREAD_NOT_ALIVE; - } - // Looks like a live JavaThread at this point. - - if (!t_list->includes(java_thread)) { - // Not on the JavaThreads list so it is not alive. - return JVMTI_ERROR_THREAD_NOT_ALIVE; - } - - // Return a live JavaThread that is "protected" by the - // ThreadsListHandle in the caller. - *jt_pp = java_thread; - - return JVMTI_ERROR_NONE; -} - class JvmtiClassFileLoadHookPoster : public StackObj { private: Symbol* _h_name; diff --git a/src/hotspot/share/prims/jvmtiExport.hpp b/src/hotspot/share/prims/jvmtiExport.hpp index e47cd3d6363db..4f8c3016908d2 100644 --- a/src/hotspot/share/prims/jvmtiExport.hpp +++ b/src/hotspot/share/prims/jvmtiExport.hpp @@ -454,8 +454,6 @@ class JvmtiExport : public AllStatic { jthread thread, JavaThread ** jt_pp, oop * thread_oop_p); - static jvmtiError cv_oop_to_JavaThread(ThreadsList * t_list, oop thread_oop, - JavaThread ** jt_pp); }; // Support class used by JvmtiDynamicCodeEventCollector and others. It diff --git a/src/hotspot/share/runtime/threadSMR.cpp b/src/hotspot/share/runtime/threadSMR.cpp index 631a7ed8d7973..c8af260f66e9f 100644 --- a/src/hotspot/share/runtime/threadSMR.cpp +++ b/src/hotspot/share/runtime/threadSMR.cpp @@ -791,10 +791,16 @@ ThreadsListHandle::~ThreadsListHandle() { // associated ThreadsList. This ThreadsListHandle "protects" the // returned JavaThread *. // +// If the jthread resolves to a virtual thread then the JavaThread * +// for its current carrier thread (if any) is returned via *jt_pp. +// It is up to the caller to prevent the virtual thread from changing +// its mounted status, or else account for it when acting on the carrier +// JavaThread. +// // If thread_oop_p is not null, then the caller wants to use the oop -// after this call so the oop is returned. On success, *jt_pp is set +// after this call so the oop is always returned. On success, *jt_pp is set // to the converted JavaThread * and true is returned. On error, -// returns false. +// returns false, and *jt_pp is unchanged. // bool ThreadsListHandle::cv_internal_thread_to_JavaThread(jobject jthread, JavaThread ** jt_pp, @@ -818,10 +824,22 @@ bool ThreadsListHandle::cv_internal_thread_to_JavaThread(jobject jthread, JavaThread *java_thread = java_lang_Thread::thread_acquire(thread_oop); if (java_thread == nullptr) { - // The java.lang.Thread does not contain a JavaThread* so it has not - // run enough to be put on a ThreadsList or it has exited enough to - // make it past ensure_join() where the JavaThread* is cleared. - return false; + if (!java_lang_VirtualThread::is_instance(thread_oop)) { + // The java.lang.Thread does not contain a JavaThread* so it has not + // run enough to be put on a ThreadsList or it has exited enough to + // make it past ensure_join() where the JavaThread* is cleared. + return false; + } else { + // For virtual threads we need to extract the carrier's JavaThread - if any. + oop carrier_thread = java_lang_VirtualThread::carrier_thread(thread_oop); + if (carrier_thread != nullptr) { + java_thread = java_lang_Thread::thread(carrier_thread); + } + if (java_thread == nullptr) { + // Virtual thread was unmounted, or else carrier has now terminated. + return false; + } + } } // Looks like a live JavaThread at this point. diff --git a/src/hotspot/share/runtime/threadSMR.hpp b/src/hotspot/share/runtime/threadSMR.hpp index a379e82058714..d2e716eaddfa3 100644 --- a/src/hotspot/share/runtime/threadSMR.hpp +++ b/src/hotspot/share/runtime/threadSMR.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,8 +45,8 @@ class ThreadsList; // operation. It is no longer necessary to hold the Threads_lock to safely // perform an operation on a target thread. // -// There are several different ways to refer to java.lang.Thread objects -// so we have a few ways to get a protected JavaThread *: +// There are two ways to refer to java.lang.Thread objects so we have two ways +// to get a protected JavaThread*: // // JNI jobject example: // jobject jthread = ...; @@ -69,21 +69,10 @@ class ThreadsList; // } // : // do stuff with 'jt'... // -// JVM/TI oop example (this one should be very rare): -// oop thread_obj = ...; -// : -// JavaThread *jt = nullptr; -// ThreadsListHandle tlh; -// jvmtiError err = JvmtiExport::cv_oop_to_JavaThread(tlh.list(), thread_obj, &jt); -// if (err != JVMTI_ERROR_NONE) { -// return err; -// } -// : // do stuff with 'jt'... -// // A JavaThread * that is included in the ThreadsList that is held by // a ThreadsListHandle is protected as long as the ThreadsListHandle -// remains in scope. The target JavaThread * may have logically exited, -// but that target JavaThread * will not be deleted until it is no +// remains in scope. The target JavaThread* may have logically exited, +// but that target JavaThread* will not be deleted until it is no // longer protected by a ThreadsListHandle. // // SMR Support for the Threads class. @@ -318,7 +307,7 @@ class ThreadsListHandle : public StackObj { inline Iterator begin(); inline Iterator end(); - bool cv_internal_thread_to_JavaThread(jobject jthread, JavaThread ** jt_pp, oop * thread_oop_p); + bool cv_internal_thread_to_JavaThread(jobject jthread, JavaThread** jt_pp, oop* thread_oop_p); bool includes(JavaThread* p) { return list()->includes(p);