Skip to content
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

(0.44) Fix virtual thread interrupts #19230

Merged
merged 2 commits into from
Mar 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 33 additions & 4 deletions runtime/jvmti/jvmtiHelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -747,19 +747,35 @@ getThreadStateHelper(J9VMThread *currentThread, j9object_t threadObject, J9VMThr
if (vmstate & J9VMTHREAD_STATE_SUSPENDED) {
state |= JVMTI_THREAD_STATE_SUSPENDED;
}

if (vmstate & J9VMTHREAD_STATE_INTERRUPTED) {
state |= JVMTI_THREAD_STATE_INTERRUPTED;
}

#if JAVA_SPEC_VERSION >= 19
/* Based on the internalSuspendState field, set the JVMTI
* thread state to suspended for the corresponding thread.
/* Based on the isSuspendedInternal field, set the JVMTI thread state to suspended for
* the corresponding thread.
*/
if (VM_VMHelpers::isThreadSuspended(currentThread, threadObject)) {
state |= JVMTI_THREAD_STATE_SUSPENDED;
} else {
state &= ~JVMTI_THREAD_STATE_SUSPENDED;
}
#endif /* JAVA_SPEC_VERSION >= 19 */
if (vmstate & J9VMTHREAD_STATE_INTERRUPTED) {

/* Thread.deadInterrupt is Thread.interrupted in OJDK's Thread implementation. In JDK19+,
* OJDK's Thread implementation is used, and multiple thread objects can be associated to
* a J9VMThread: a virtual thread and its carrier thread. If a virtual thread is mounted,
* then the carrier thread is unmounted and vice-versa. In such cases, J9VMThread's state
* should not be used to determine if a thread object is interrupted. Instead,
* Thread.interrupted is used to determine if a thread object is interrupted.
*/
if (J9VMJAVALANGTHREAD_DEADINTERRUPT(currentThread, threadObject)) {
state |= JVMTI_THREAD_STATE_INTERRUPTED;
} else {
state &= ~JVMTI_THREAD_STATE_INTERRUPTED;
}
#endif /* JAVA_SPEC_VERSION >= 19 */

#if defined(J9VM_INTERP_ATOMIC_FREE_JNI)
if (vmThread->inNative) {
state |= JVMTI_THREAD_STATE_IN_NATIVE;
Expand Down Expand Up @@ -899,6 +915,19 @@ getVirtualThreadState(J9VMThread *currentThread, jthread thread)
} else {
rc &= ~JVMTI_THREAD_STATE_SUSPENDED;
}

/* Thread.deadInterrupt is Thread.interrupted in OJDK's Thread implementation. In JDK19+,
* OJDK's Thread implementation is used, and multiple thread objects can be associated to
* a J9VMThread: a virtual thread and its carrier thread. If a virtual thread is mounted,
* then the carrier thread is unmounted and vice-versa. In such cases, J9VMThread's state
* should not be used to determine if a thread object is interrupted. Instead,
* Thread.interrupted is used to determine if a thread object is interrupted.
*/
if (J9VMJAVALANGTHREAD_DEADINTERRUPT(currentThread, vThreadObject)) {
rc |= JVMTI_THREAD_STATE_INTERRUPTED;
} else {
rc &= ~JVMTI_THREAD_STATE_INTERRUPTED;
}
releaseVMThread(currentThread, targetThread, thread);
} else {
/* This is unreachable. */
Expand Down
40 changes: 37 additions & 3 deletions runtime/oti/VMHelpers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1410,8 +1410,24 @@ class VM_VMHelpers
{
J9VMThread *targetThread = J9VMJAVALANGTHREAD_THREADREF(currentThread, threadObject);
bool result = false;
#if JAVA_SPEC_VERSION >= 19
/* Check if the mounted thread is suspended. */
bool isSuspended = false;
if (NULL != targetThread) {
isSuspended = isThreadSuspended(currentThread, targetThread->threadObject);
}
#endif /* JAVA_SPEC_VERSION >= 19 */
/* If the thread is alive, ask the OS thread. Otherwise, answer false. */
if (J9VMJAVALANGTHREAD_STARTED(currentThread, threadObject) && (NULL != targetThread)) {
if ((NULL != targetThread)
&& J9VMJAVALANGTHREAD_STARTED(currentThread, threadObject)
#if JAVA_SPEC_VERSION >= 19
/* Thread.deadInterrupt is Thread.interrupted in OJDK's Thread implementation.
* In JDK19+, OJDK's Thread implementation is used. If the mounted thread is
* suspended, use Thread.interrupted to derive if the thread is interrupted.
*/
&& (!isSuspended)
#endif /* JAVA_SPEC_VERSION >= 19 */
) {
if (omrthread_interrupted(targetThread->osThread)) {
result = true;
}
Expand Down Expand Up @@ -2043,8 +2059,26 @@ class VM_VMHelpers
threadInterruptImpl(J9VMThread *currentThread, j9object_t targetObject)
{
J9VMThread *targetThread = J9VMJAVALANGTHREAD_THREADREF(currentThread, targetObject);
if (J9VMJAVALANGTHREAD_STARTED(currentThread, targetObject) && (NULL != targetThread)) {
void (*sidecarInterruptFunction)(J9VMThread*) = currentThread->javaVM->sidecarInterruptFunction;
J9JavaVM *vm = currentThread->javaVM;
#if JAVA_SPEC_VERSION >= 19
/* Check if the mounted thread is suspended. */
bool isSuspended = false;
if (NULL != targetThread) {
isSuspended = isThreadSuspended(currentThread, targetThread->threadObject);
}
#endif /* JAVA_SPEC_VERSION >= 19 */
if ((NULL != targetThread)
&& J9VMJAVALANGTHREAD_STARTED(currentThread, targetObject)
#if JAVA_SPEC_VERSION >= 19
/* Thread.deadInterrupt is Thread.interrupted in OJDK's Thread implementation.
* In JDK19+, OJDK's Thread implementation is used. If the mounted thread is
* suspended, only set Thread.interrupted to TRUE and do not wake/interrupt
* the thread.
*/
&& (!isSuspended)
#endif /* JAVA_SPEC_VERSION >= 19 */
) {
void (*sidecarInterruptFunction)(J9VMThread*) = vm->sidecarInterruptFunction;
if (NULL != sidecarInterruptFunction) {
sidecarInterruptFunction(targetThread);
}
Expand Down