From dfb02ce31455086bb26d1fb6c90f35b88820c2c0 Mon Sep 17 00:00:00 2001 From: Babneet Singh Date: Tue, 19 Dec 2023 18:43:24 -0800 Subject: [PATCH 1/2] Acquire VThreadInspector before vmThreadListMutex to avoid deadlock VirtualThreads.park performs operations in the below order: Set VThreadInspector to -1 and then acquire vmThreadListMutex JVMTI GetThreadState -> ... -> getVMThread follows the below order: Acquire vmThreadListMutex and then spin until VThreadInspector != -1 A deadlock occurs because the order of operations is inconsistent between VirtualThreads.park and JVMTI GetThreadState. To resolve the deadlock, the operations in getVMThread are swapped to match the operations in VirtualThreads.park: Acquire VThreadInspector and then acquire vmThreadListMutex Related: #18642 Signed-off-by: Babneet Singh --- runtime/jvmti/jvmtiHelpers.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/runtime/jvmti/jvmtiHelpers.cpp b/runtime/jvmti/jvmtiHelpers.cpp index de5338a01b9..104ab11bb2b 100644 --- a/runtime/jvmti/jvmtiHelpers.cpp +++ b/runtime/jvmti/jvmtiHelpers.cpp @@ -148,16 +148,21 @@ getVMThread(J9VMThread *currentThread, jthread thread, J9VMThread **vmThreadPtr, } } +#if JAVA_SPEC_VERSION >= 19 + isVirtualThread = IS_JAVA_LANG_VIRTUALTHREAD(currentThread, threadObject); + if (isVirtualThread) { + vm->internalVMFunctions->acquireVThreadInspector(currentThread, thread, TRUE); + /* Re-fetch threadObject since acquireVThreadInspector can release and reacquire VM access. */ + threadObject = J9_JNI_UNWRAP_REFERENCE(thread); + } +#endif /* JAVA_SPEC_VERSION >= 19 */ + /* Make sure the vmThread stays alive while it is being used. */ omrthread_monitor_enter(vm->vmThreadListMutex); #if JAVA_SPEC_VERSION >= 19 - isVirtualThread = IS_JAVA_LANG_VIRTUALTHREAD(currentThread, threadObject); if (isVirtualThread) { jint vthreadState = 0; j9object_t carrierThread = NULL; - vm->internalVMFunctions->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) { @@ -173,12 +178,12 @@ getVMThread(J9VMThread *currentThread, jthread thread, J9VMThread **vmThreadPtr, if (!isThreadAlive) { if (OMR_ARE_ANY_BITS_SET(flags, J9JVMTI_GETVMTHREAD_ERROR_ON_DEAD_THREAD)) { + omrthread_monitor_exit(vm->vmThreadListMutex); #if JAVA_SPEC_VERSION >= 19 if (isVirtualThread) { vm->internalVMFunctions->releaseVThreadInspector(currentThread, thread); } #endif /* JAVA_SPEC_VERSION >= 19 */ - omrthread_monitor_exit(vm->vmThreadListMutex); return JVMTI_ERROR_THREAD_NOT_ALIVE; } } From f50d655b1b80d455aa95a6cecd870e4c2b5692c3 Mon Sep 17 00:00:00 2001 From: Babneet Singh Date: Tue, 19 Dec 2023 16:10:14 -0800 Subject: [PATCH 2/2] VirtualThread State: *PINNED is identical to *PARKED RI and JTReg tests expect the same JVMTI thread state for - PARKED and PINNED - TIMED_PARKED and TIMED_PINNED Related: #18642 Signed-off-by: Babneet Singh --- runtime/jvmti/jvmtiHelpers.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/runtime/jvmti/jvmtiHelpers.cpp b/runtime/jvmti/jvmtiHelpers.cpp index 104ab11bb2b..46910703a76 100644 --- a/runtime/jvmti/jvmtiHelpers.cpp +++ b/runtime/jvmti/jvmtiHelpers.cpp @@ -866,18 +866,14 @@ getVirtualThreadState(J9VMThread *currentThread, jthread thread) case JVMTI_VTHREAD_STATE_YIELDING: rc = JVMTI_JAVA_LANG_THREAD_STATE_RUNNABLE; break; + case JVMTI_VTHREAD_STATE_PINNED: case JVMTI_VTHREAD_STATE_PARKED: rc = JVMTI_JAVA_LANG_THREAD_STATE_WAITING | JVMTI_THREAD_STATE_PARKED; break; + case JVMTI_VTHREAD_STATE_TIMED_PINNED: case JVMTI_VTHREAD_STATE_TIMED_PARKED: rc = JVMTI_JAVA_LANG_THREAD_STATE_TIMED_WAITING | JVMTI_THREAD_STATE_PARKED; break; - case JVMTI_VTHREAD_STATE_PINNED: - rc = JVMTI_JAVA_LANG_THREAD_STATE_WAITING; - break; - case JVMTI_VTHREAD_STATE_TIMED_PINNED: - rc = JVMTI_JAVA_LANG_THREAD_STATE_TIMED_WAITING; - break; case JVMTI_VTHREAD_STATE_TERMINATED: rc = JVMTI_JAVA_LANG_THREAD_STATE_TERMINATED; break;