Skip to content

Commit

Permalink
Update the fully mounted check in JVMTI Suspend/Resume Thread
Browse files Browse the repository at this point in the history
During JVMTI suspend/resume thread operations, the current check to
determine if a thread is fully mounted is flaky. It depends on
J9VMThread->theadObject which might change after getVMThread due to
Java level changes, which are accepted as-is from the RI.

The check to determine if a thread is fully mounted is moved into
getVMThread. The check is updated to use the continuation state, which
is more stable since the Continuation implementation is maintained
within OpenJ9.

Related: eclipse-openj9#17865
Related: eclipse-openj9#17869
Related: eclipse-openj9#18370

Signed-off-by: Babneet Singh <[email protected]>
  • Loading branch information
babsingh committed Nov 14, 2023
1 parent 5fde7f7 commit 1cd50dd
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 10 deletions.
15 changes: 11 additions & 4 deletions runtime/jvmti/jvmtiHelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ getVMThread(J9VMThread *currentThread, jthread thread, J9VMThread **vmThreadPtr,
BOOLEAN isThreadAlive = FALSE;
#if JAVA_SPEC_VERSION >= 19
BOOLEAN isVirtualThread = FALSE;
J9InternalVMFunctions const * const vmfuncs = vm->internalVMFunctions;
#endif /* JAVA_SPEC_VERSION >= 19 */

if (NULL == thread) {
Expand Down Expand Up @@ -155,14 +156,20 @@ getVMThread(J9VMThread *currentThread, jthread thread, J9VMThread **vmThreadPtr,
if (isVirtualThread) {
jint vthreadState = 0;
j9object_t carrierThread = NULL;
vm->internalVMFunctions->acquireVThreadInspector(currentThread, thread, TRUE);

vmfuncs->acquireVThreadInspector(currentThread, thread, TRUE);

/* Re-fetch threadObject since acquireVThreadInspector can release and reacquire VM access. */
threadObject = J9_JNI_UNWRAP_REFERENCE(thread);
vthreadState = J9VMJAVALANGVIRTUALTHREAD_STATE(currentThread, threadObject);
carrierThread = (j9object_t)J9VMJAVALANGVIRTUALTHREAD_CARRIERTHREAD(currentThread, threadObject);
if (NULL != carrierThread) {

if ((NULL != carrierThread)
&& vmfuncs->isVThreadFullyMounted(currentThread, threadObject)
) {
targetThread = J9VMJAVALANGTHREAD_THREADREF(currentThread, carrierThread);
}

vthreadState = J9VMJAVALANGVIRTUALTHREAD_STATE(currentThread, threadObject);
isThreadAlive = (JVMTI_VTHREAD_STATE_NEW != vthreadState) && (JVMTI_VTHREAD_STATE_TERMINATED != vthreadState);
} else
#endif /* JAVA_SPEC_VERSION >= 19 */
Expand All @@ -175,7 +182,7 @@ getVMThread(J9VMThread *currentThread, jthread thread, J9VMThread **vmThreadPtr,
if (OMR_ARE_ANY_BITS_SET(flags, J9JVMTI_GETVMTHREAD_ERROR_ON_DEAD_THREAD)) {
#if JAVA_SPEC_VERSION >= 19
if (isVirtualThread) {
vm->internalVMFunctions->releaseVThreadInspector(currentThread, thread);
vmfuncs->releaseVThreadInspector(currentThread, thread);
}
#endif /* JAVA_SPEC_VERSION >= 19 */
omrthread_monitor_exit(vm->vmThreadListMutex);
Expand Down
14 changes: 9 additions & 5 deletions runtime/jvmti/jvmtiThread.c
Original file line number Diff line number Diff line change
Expand Up @@ -1139,10 +1139,9 @@ resumeThread(J9VMThread *currentThread, jthread thread)
J9JavaVM *vm = currentThread->javaVM;
j9object_t threadObject = J9_JNI_UNWRAP_REFERENCE(thread);
/* The J9_PUBLIC_FLAGS_HALT_THREAD_JAVA_SUSPEND will be cleared only
* if the thread is resumed and it has been mounted
* i.e. threadObject == targetThread->threadObject.
* if the thread is resumed and it has been mounted.
*/
if ((NULL != targetThread) && (threadObject == targetThread->threadObject))
if (NULL != targetThread)
#endif /* JAVA_SPEC_VERSION >= 19 */
{
if (OMR_ARE_ANY_BITS_SET(targetThread->publicFlags, J9_PUBLIC_FLAGS_HALT_THREAD_JAVA_SUSPEND)) {
Expand Down Expand Up @@ -1341,12 +1340,17 @@ jvmtiSuspendResumeCallBack(J9VMThread *vmThread, J9MM_IterateObjectDescriptor *o
J9JavaVM *vm = vmThread->javaVM;
J9VMThread *targetThread = NULL;
j9object_t carrierThread = (j9object_t)J9VMJAVALANGVIRTUALTHREAD_CARRIERTHREAD(vmThread, vthread);
BOOLEAN isFullyMounted = FALSE;
if (NULL != carrierThread) {
targetThread = J9VMJAVALANGTHREAD_THREADREF(vmThread, carrierThread);
if (NULL != targetThread) {
isFullyMounted = vm->internalVMFunctions->isVThreadFullyMounted(vmThread, vthread);
}
Assert_JVMTI_notNull(targetThread);
}
if (data->is_suspend) {
if ((NULL != targetThread) && (vthread == targetThread->threadObject)) {
/* Suspend the virtual thread. */
if ((NULL != targetThread) && isFullyMounted) {
if (OMR_ARE_NO_BITS_SET(targetThread->publicFlags, J9_PUBLIC_FLAGS_HALT_THREAD_JAVA_SUSPEND | J9_PUBLIC_FLAGS_STOPPED)) {
setHaltFlag(targetThread, J9_PUBLIC_FLAGS_HALT_THREAD_JAVA_SUSPEND);
Trc_JVMTI_threadSuspended(targetThread);
Expand All @@ -1355,7 +1359,7 @@ jvmtiSuspendResumeCallBack(J9VMThread *vmThread, J9MM_IterateObjectDescriptor *o
J9OBJECT_U32_STORE(vmThread, vthread, vm->isSuspendedInternalOffset, 1);
} else {
/* Resume the virtual thread. */
if ((NULL != targetThread) && (vthread == targetThread->threadObject)) {
if ((NULL != targetThread) && isFullyMounted) {
if (OMR_ARE_ANY_BITS_SET(targetThread->publicFlags, J9_PUBLIC_FLAGS_HALT_THREAD_JAVA_SUSPEND)) {
clearHaltFlag(targetThread, J9_PUBLIC_FLAGS_HALT_THREAD_JAVA_SUSPEND);
Trc_JVMTI_threadResumed(targetThread);
Expand Down
2 changes: 1 addition & 1 deletion runtime/jvmti/suspendhelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ suspendThread(J9VMThread *currentThread, jthread thread, BOOLEAN allowNull, BOOL
/* The J9 PUBLIC FLAGS HALT THREAD JAVA SUSPEND flag will be set
* if the thread is mounted.
*/
if ((NULL != targetThread) && (threadObject == targetThread->threadObject))
if (NULL != targetThread)
#endif /* JAVA_SPEC_VERSION >= 19 */
{
if (OMR_ARE_ANY_BITS_SET(targetThread->publicFlags, J9_PUBLIC_FLAGS_HALT_THREAD_JAVA_SUSPEND)) {
Expand Down
1 change: 1 addition & 0 deletions runtime/oti/j9nonbuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -5059,6 +5059,7 @@ typedef struct J9InternalVMFunctions {
UDATA (*walkAllStackFrames)(struct J9VMThread *currentThread, J9StackWalkState *walkState);
BOOLEAN (*acquireVThreadInspector)(struct J9VMThread *currentThread, jobject thread, BOOLEAN spin);
void (*releaseVThreadInspector)(struct J9VMThread *currentThread, jobject thread);
BOOLEAN (*isVThreadFullyMounted)(struct J9VMThread *currentThread, j9object_t vThread);
#endif /* JAVA_SPEC_VERSION >= 19 */
UDATA (*checkArgsConsumed)(struct J9JavaVM * vm, struct J9PortLibrary* portLibrary, struct J9VMInitArgs* j9vm_args);
#if defined(J9VM_ZOS_3164_INTEROPERABILITY) && (JAVA_SPEC_VERSION >= 17)
Expand Down
11 changes: 11 additions & 0 deletions runtime/oti/vm_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -4518,6 +4518,17 @@ acquireVThreadInspector(J9VMThread *currentThread, jobject thread, BOOLEAN spin)
*/
void
releaseVThreadInspector(J9VMThread *currentThread, jobject thread);

/**
* @brief Check if the virtual thread is fully mounted. If a virtual thread
* is not provided, FALSE is returned.
*
* @param currentThread current thread
* @param vThread the virtual thread
* @return TRUE if it is mounted and FALSE if unmounted
*/
BOOLEAN
isVThreadFullyMounted(J9VMThread *currentThread, j9object_t vThread);
#endif /* JAVA_SPEC_VERSION >= 19 */

/* ---------------- hookableAsync.c ---------------- */
Expand Down
13 changes: 13 additions & 0 deletions runtime/vm/ContinuationHelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -585,4 +585,17 @@ releaseVThreadInspector(J9VMThread *currentThread, jobject thread)
vthreadInspectorCount = J9OBJECT_I64_LOAD(currentThread, threadObj, vm->virtualThreadInspectorCountOffset);
}
}

BOOLEAN
isVThreadFullyMounted(J9VMThread *currentThread, j9object_t vThread)
{
if (IS_JAVA_LANG_VIRTUALTHREAD(currentThread, vThread)) {
/* Return FALSE if a virtual thread is not provided. */
return FALSE;
}

j9object_t continuationObj = (j9object_t)J9VMJAVALANGVIRTUALTHREAD_CONT(currentThread, vThread);
ContinuationState continuationState = J9VMJDKINTERNALVMCONTINUATION_STATE(currentThread, continuationObj);
return VM_ContinuationHelpers::isFullyMounted(continuationState);
}
} /* extern "C" */
1 change: 1 addition & 0 deletions runtime/vm/intfunc.c
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,7 @@ J9InternalVMFunctions J9InternalFunctions = {
walkAllStackFrames,
acquireVThreadInspector,
releaseVThreadInspector,
isVThreadFullyMounted,
#endif /* JAVA_SPEC_VERSION >= 19 */
checkArgsConsumed,
#if defined(J9VM_ZOS_3164_INTEROPERABILITY) && (JAVA_SPEC_VERSION >= 17)
Expand Down

0 comments on commit 1cd50dd

Please sign in to comment.