8361912: ThreadsListHandle::cv_internal_thread_to_JavaThread does not deal with a virtual thread's carrier thread

Reviewed-by: pchilanomate, dcubed, amenkov, sspitsyn
This commit is contained in:
David Holmes 2025-07-28 23:47:51 +00:00
parent 3e4e5dd06f
commit 4669005123
4 changed files with 30 additions and 66 deletions

View File

@ -865,47 +865,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;

View File

@ -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

View File

@ -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.

View File

@ -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 @@ public:
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);