-
Notifications
You must be signed in to change notification settings - Fork 6.1k
8361912: ThreadsListHandle::cv_internal_thread_to_JavaThread does not deal with a virtual thread's carrier thread #26287
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
8099035
4ed9035
9e13596
5d7eb80
a195fe2
820f26e
d863add
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: If I have one concern here. Nothing protects this code from facing some unexpected conditions as this function is racy with mounting and unmounting of target virtual thread
So, it seems that this function is going to work correctly if used for target platform threads only or if the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The java_thread can be null because the carrier of a mounted vthread was not contained in the ThreadsListHandle. The only thing this function guarantees is that if the vthread appeared to have a carrier and that carrier is protected by the TLH, then the caller can safely interact with the carrier knowing it can't terminate - same as for regular threads. The caller has to account for the potential async mounting/unmounting of vthread - e.g. by handshaking the reported carrier and then confirming it is still the carrier. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks, David. The potential issue I'm still concerned about is that a subsequent handshaking can also observe the JavaThread (and virtual thread as well) in a VTMS transition when there is no protection with a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Right. I guess, this answers my comment about the line 839. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Once in the handshake the carrier (and thus virtual thread) is "frozen" with regards to any transition. It could be anywhere in the process of mounting/unmounting (depending of course exactly where the carrier might respond to the handshake request), and the actual handshake operation has to deal with that. But that is true no matter how you extracted a reference to the carrier. As I said before the only thing this change guarantees is that the carrier is protected by the TLH and can't fully terminate whilst handshaking with it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Okay, thanks. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Once this change is in main line then we can sync'up the loom repo and work on the follow-up changes. The loom repo has changes (that are not in main line) for "suspending" an unmounted thread. For the mounted case then we'll need checks in the handshake to ensure that the expected virtual threads is mounted. We'll need stress tests of course and we can collaborate there in advance of proposing changes for main line. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I'm having some trouble with this statement. Working backwards from L836, I see So I guess I'm not sure what point you're trying to make with the statement. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Sure. My point was more the other way round - we could have a null JavaThread without the null coming from line 836. The comment was just trying to expand on my previous comment. |
||
return false; | ||
} | ||
} | ||
} | ||
// Looks like a live JavaThread at this point. | ||
|
||
|
Uh oh!
There was an error while loading. Please reload this page.