Skip to content

Commit

Permalink
Merge pull request #19230 from babsingh/0.44_backports
Browse files Browse the repository at this point in the history
Fix virtual thread interrupts
  • Loading branch information
pshipton authored Mar 26, 2024
2 parents afb3132 + 41fb9ef commit 2e56066
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 7 deletions.
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

0 comments on commit 2e56066

Please sign in to comment.