diff --git a/runtime/jvmti/jvmtiClass.c b/runtime/jvmti/jvmtiClass.c index 9df7c6b92bb..5de4e8eeffa 100644 --- a/runtime/jvmti/jvmtiClass.c +++ b/runtime/jvmti/jvmtiClass.c @@ -1233,10 +1233,14 @@ redefineClassesCommon(jvmtiEnv* env, /* Eliminate dark matter so that none will be encountered in prepareToFixMemberNames(). */ UDATA savedAllowUserHeapWalkFlag = vm->requiredDebugAttributes & J9VM_DEBUG_ATTRIBUTE_ALLOW_USER_HEAP_WALK; vm->requiredDebugAttributes |= J9VM_DEBUG_ATTRIBUTE_ALLOW_USER_HEAP_WALK; - /* J9MMCONSTANT_EXPLICIT_GC_RASDUMP_COMPACT allows the GC to run while the current thread is holding - * exclusive VM access. - */ - vm->memoryManagerFunctions->j9gc_modron_global_collect_with_overrides(currentThread, J9MMCONSTANT_EXPLICIT_GC_RASDUMP_COMPACT); + + /* This is to help with Metronome to avoid requesting Exclusive if we already have SafePoint, which may not look as Exclusive to the requester thread */ + vm->alreadyHaveExclusive = TRUE; + + vm->memoryManagerFunctions->j9gc_modron_global_collect_with_overrides(currentThread, J9MMCONSTANT_EXPLICIT_GC_EXCLUSIVE_VMACCESS_ALREADY_ACQUIRED); + + vm->alreadyHaveExclusive = FALSE; + if (0 == savedAllowUserHeapWalkFlag) { /* Clear the flag to restore its original value. */ vm->requiredDebugAttributes &= ~J9VM_DEBUG_ATTRIBUTE_ALLOW_USER_HEAP_WALK; diff --git a/runtime/oti/j9nonbuilder.h b/runtime/oti/j9nonbuilder.h index faa869345fb..d28b583907d 100644 --- a/runtime/oti/j9nonbuilder.h +++ b/runtime/oti/j9nonbuilder.h @@ -5912,6 +5912,7 @@ typedef struct J9JavaVM { UDATA addModulesCount; UDATA safePointState; UDATA safePointResponseCount; + BOOLEAN alreadyHaveExclusive; struct J9VMRuntimeStateListener vmRuntimeStateListener; #if defined(J9VM_INTERP_ATOMIC_FREE_JNI_USES_FLUSH) #if defined(J9UNIX) || defined(AIXPPC) diff --git a/runtime/vm/VMAccess.cpp b/runtime/vm/VMAccess.cpp index 4e2b2b00ea0..4969e89375f 100644 --- a/runtime/vm/VMAccess.cpp +++ b/runtime/vm/VMAccess.cpp @@ -755,6 +755,11 @@ acquireExclusiveVMAccessFromExternalThread(J9JavaVM * vm) UDATA vmResponsesExpected = 0; UDATA jniResponsesExpected = 0; + /* If exclusive has already been acquired, nothing need be done here */ + if (vm->alreadyHaveExclusive) { + return; + } + synchronizeRequestsFromExternalThread(vm, TRUE); /* Post the halt request to all threads */ @@ -836,6 +841,12 @@ void releaseExclusiveVMAccessFromExternalThread(J9JavaVM * vm) { J9VMThread * currentThread; + + /* If exclusive has already been acquired, nothing need be done here */ + if (vm->alreadyHaveExclusive) { + return; + } + Assert_VM_true(J9_XACCESS_EXCLUSIVE == vm->exclusiveAccessState); /* Acquire these monitors in the same order as in allocateVMThread to prevent deadlock */ @@ -913,6 +924,11 @@ requestExclusiveVMAccessMetronomeTemp(J9JavaVM *vm, UDATA block, UDATA *vmRespon UDATA jniResponsesExpected = 0; *gcPriority = J9THREAD_PRIORITY_MAX; + /* If exclusive has already been acquired, nothing need be done here */ + if (vm->alreadyHaveExclusive) { + return FALSE; + } + /* Check if another party is requesting X access already. */ if (FALSE == synchronizeRequestsFromExternalThread(vm, block)) { /* Yes, there was another party requesting X access, but because we did not want to block, @@ -1010,7 +1026,14 @@ waitForExclusiveVMAccessMetronome(J9VMThread * vmThread, UDATA responsesRequired void waitForExclusiveVMAccessMetronomeTemp(J9VMThread * vmThread, UDATA vmResponsesRequired, UDATA jniResponsesRequired) { - waitForResponseFromExternalThread(vmThread->javaVM, vmResponsesRequired, jniResponsesRequired); + J9JavaVM *vm = vmThread->javaVM; + + /* If exclusive has already been acquired, nothing need be done here */ + if (vm->alreadyHaveExclusive) { + return; + } + + waitForResponseFromExternalThread(vm, vmResponsesRequired, jniResponsesRequired); VM_VMAccess::backOffFromSafePoint(vmThread);