Skip to content

Commit

Permalink
Patch MXBean to support virtual threads
Browse files Browse the repository at this point in the history
Use carrierThreadObject instead of threadObject for Java 19.

For thread with a virtual thread mount that is waiting on a lock,
we should return the virtualthreadobject as lock object/owner.

Signed-off-by: Gengchen Tuo <gengchen.tuo@ibm.com>
  • Loading branch information
thallium committed Oct 21, 2022
1 parent 2b8eca6 commit ce4d4a3
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 26 deletions.
75 changes: 51 additions & 24 deletions runtime/jcl/common/mgmtthread.c
Original file line number Diff line number Diff line change
Expand Up @@ -227,15 +227,17 @@ Java_com_ibm_java_lang_management_internal_ThreadMXBeanImpl_getAllThreadIdsImpl(
/* Grab any thread (mainThread will do) */
currentThread = javaVM->mainThread;
/* Loop over all vmThreads until we get back to the starting thread: Count phase */
threadCount = 0;
do {
{
if ((currentThread->threadObject != NULL) && (J9VMJAVALANGTHREAD_THREADREF((J9VMThread *)env,currentThread->threadObject) != NULL)) {
/* CMVC 182865 - exclude threads which have not initialized their ID */
jlong threadID = getThreadID((J9VMThread *)env, (j9object_t)currentThread->threadObject);
if (((jlong)0) != threadID) {
threadIDs[threadCount++] = threadID;
}
#if JAVA_SPEC_VERSION >= 19
j9object_t threadObject = currentThread->carrierThreadObject;
#else /* JAVA_SPEC_VERSION >= 19 */
j9object_t threadObject = currentThread->threadObject;
#endif /* JAVA_SPEC_VERSION >= 19 */
if ((NULL != threadObject) && (NULL != J9VMJAVALANGTHREAD_THREADREF((J9VMThread *)env, threadObject))) {
/* CMVC 182865 - exclude threads which have not initialized their ID */
jlong threadID = getThreadID((J9VMThread *)env, threadObject);
if (((jlong)0) != threadID) {
threadIDs[threadCount++] = threadID;
}
}
} while ((currentThread = currentThread->linkNext) != javaVM->mainThread);
Expand Down Expand Up @@ -937,24 +939,27 @@ getThread(JNIEnv *env, jlong threadID)
currentThread = javaVM->mainThread;
/* Loop over all vmThreads until we get back to the starting thread: look for matching threadID */
while (TRUE) {
if ((currentThread->threadObject != NULL) && (getThreadID((J9VMThread *)env, (j9object_t)currentThread->threadObject) == threadID)) {
{
/*
* We've found our matching thread, so we're done.
* But first we have to check if the thread is alive
* i.e. The j.l.Thread object's thread ref != 0
*/
if (J9VMJAVALANGTHREAD_THREADREF((J9VMThread *)env,currentThread->threadObject) == NULL) {
currentThread = NULL;
}
return currentThread;
#if JAVA_SPEC_VERSION >= 19
j9object_t threadObject = currentThread->carrierThreadObject;
#else /* JAVA_SPEC_VERSION >= 19 */
j9object_t threadObject = currentThread->threadObject;
#endif /* JAVA_SPEC_VERSION >= 19 */
if ((NULL != threadObject) && (threadID == getThreadID((J9VMThread *)env, threadObject))) {
/*
* We've found our matching thread, so we're done.
* But first we have to check if the thread is alive
* i.e. The j.l.Thread object's thread ref != 0
*/
if (NULL == J9VMJAVALANGTHREAD_THREADREF((J9VMThread *)env, threadObject)) {
currentThread = NULL;
}
return currentThread;
}

if ((currentThread = currentThread->linkNext) == javaVM->mainThread) {
/* Back at starting thread with no match, so return NULL */
return NULL;
}
}
}
}

Expand Down Expand Up @@ -1317,15 +1322,25 @@ getThreadInfo(J9VMThread *currentThread, J9VMThread *targetThread, ThreadInfo *i
j9object_t monitorOwnerObject = NULL;
IDATA exc = 0; /* exception index */

#if JAVA_SPEC_VERSION >= 19
J9VMThread stackThread = {0};
J9VMEntryLocalStorage els = {0};
J9VMContinuation *continuation = targetThread->currentContinuation;
j9object_t threadObject = currentThread->carrierThreadObject;
#else /* JAVA_SPEC_VERSION >= 19 */
j9object_t threadObject = currentThread->threadObject;
#endif /* JAVA_SPEC_VERSION >= 19 */

Trc_JCL_threadmxbean_getThreadInfo_Entry(currentThread, targetThread);

info->thread =
vmfns->j9jni_createLocalRef((JNIEnv *)currentThread, (j9object_t)targetThread->threadObject);
info->thread = vmfns->j9jni_createLocalRef((JNIEnv *)currentThread, threadObject);

This comment has been minimized.

Copy link
@pshipton

pshipton Oct 24, 2022

Member

The original code used targetThread->threadObject and this modifies it to currentThread->threadObject.

#14538 (comment)

This comment has been minimized.

Copy link
@pshipton

pshipton Oct 24, 2022

Member

Not just here, but other other two places that were modified as well were originally targetThread->threadObject

This comment has been minimized.

Copy link
@babsingh

babsingh Oct 24, 2022

Contributor

I will make the correction since there was a typo in my feedback #15956 (comment) while copy-pasting. fyi @thallium @fengxue-IS

This comment has been minimized.

Copy link
@thallium

thallium Oct 24, 2022

Author Contributor

Thank you

/* Set the native thread ID available through the thread library. */
info->nativeTID = (jlong) omrthread_get_osId(targetThread->osThread);
info->vmstate = getVMThreadObjectState(targetThread, &monitorObject, &monitorOwner, NULL);
if (targetThread->threadObject) {
info->jclThreadState = getJclThreadState(info->vmstate, J9VMJAVALANGTHREAD_STARTED(currentThread, targetThread->threadObject));
if (NULL != threadObject) {
info->jclThreadState = getJclThreadState(
info->vmstate,
J9VMJAVALANGTHREAD_STARTED(currentThread, threadObject));
} else {
info->jclThreadState = getJclThreadState(info->vmstate, JNI_TRUE);
}
Expand All @@ -1344,6 +1359,18 @@ getThreadInfo(J9VMThread *currentThread, J9VMThread *targetThread, ThreadInfo *i

/* this may block on vm->managementDataLock */
getContentionStats(currentThread, targetThread, info);
#if JAVA_SPEC_VERSION >= 19
/* getStackFramePCs needs to run on the carrier thread's stack to produce the right output.
* For threads with a continuation mounted, copy the carrier thread's stack data from the
* continuation to a stack allocated J9VMThread structure. To avoid potential dependencies
* on targetThread pointer's address, the stack allocated thread is only used for getStackFramePCs.
*/
if (NULL != continuation) {
memcpy(&stackThread, targetThread, sizeof(J9VMThread));
vm->internalVMFunctions->copyFieldsFromContinuation(currentThread, &stackThread, &els, continuation);
targetThread = &stackThread;
}
#endif /* JAVA_SPEC_VERSION >= 19 */

exc = getStackFramePCs(currentThread, targetThread, info);
if (exc > 0) {
Expand Down
21 changes: 19 additions & 2 deletions runtime/util/thrinfo.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 1991, 2020 IBM Corp. and others
* Copyright (c) 1991, 2022 IBM Corp. and others
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
Expand Down Expand Up @@ -287,7 +287,24 @@ getVMThreadStateHelper(J9VMThread *targetThread,
*/
}
}


#if JAVA_SPEC_VERSION >= 19
/* For a J9VMThread with a mounted virtual thread that is waiting on a
* lock, the virtual thread object should be returned as the lock object
* and the corresponding J9VMThread should be returned as the lock
* owner.
*
* ThreadMXBean documentation states that it does not support VirtualThread
* and behaviour on locks, related to VirtualThread, has not been defined.
* This code matches the RI's ThreadMXBean API behaviour.
*/
if (((J9VMTHREAD_STATE_WAITING == vmstate) || (J9VMTHREAD_STATE_WAITING_TIMED == vmstate))
&& (NULL != targetThread->currentContinuation)
) {
lockObject = targetThread->threadObject;
lockOwner = targetThread;
}
#endif /* JAVA_SPEC_VERSION >= 19 */
} else {
/*
* Can't wait on an uninflated object monitor, so the thread
Expand Down

0 comments on commit ce4d4a3

Please sign in to comment.