diff --git a/runtime/jcl/common/jdk_internal_misc_ScopedMemoryAccess.cpp b/runtime/jcl/common/jdk_internal_misc_ScopedMemoryAccess.cpp index e61a595e393..4eac6a65891 100644 --- a/runtime/jcl/common/jdk_internal_misc_ScopedMemoryAccess.cpp +++ b/runtime/jcl/common/jdk_internal_misc_ScopedMemoryAccess.cpp @@ -86,6 +86,8 @@ Java_jdk_internal_misc_ScopedMemoryAccess_closeScope0(JNIEnv *env, jobject insta setHaltFlag(walkThread, J9_PUBLIC_FLAGS_CLOSE_SCOPE); walkThread->scopedError = errorObj; walkThread->closeScopeObj = closeScopeObj; + /* Atomic add is not needed since exclusive VM access has been acquired. */ + vm->closeScopeNotifyCount += 1; #else /* JAVA_SPEC_VERSION >= 22 */ scopeFound = JNI_TRUE; break; @@ -99,6 +101,21 @@ Java_jdk_internal_misc_ScopedMemoryAccess_closeScope0(JNIEnv *env, jobject insta } vmFuncs->internalExitVMToJNI(currentThread); + +#if JAVA_SPEC_VERSION >= 22 + /* There are gaps where async exceptions are not processed in time + * (e.g. JIT compiled code in a loop). Wait until J9VMThread->scopedError + * (async exception) is transferred to J9VMThread->currentException. The + * wait prevents a MemorySession to be closed until no more operations are + * being performed on it. + */ + omrthread_monitor_enter(vm->closeScopeMutex); + while (0 != vm->closeScopeNotifyCount) { + omrthread_monitor_wait(vm->closeScopeMutex); + } + omrthread_monitor_exit(vm->closeScopeMutex); +#endif /* JAVA_SPEC_VERSION >= 22 */ + #if JAVA_SPEC_VERSION <= 21 return !scopeFound; #endif /* JAVA_SPEC_VERSION <= 21 */ diff --git a/runtime/oti/j9nonbuilder.h b/runtime/oti/j9nonbuilder.h index 453b57cb688..75418d924d5 100644 --- a/runtime/oti/j9nonbuilder.h +++ b/runtime/oti/j9nonbuilder.h @@ -6049,6 +6049,10 @@ typedef struct J9JavaVM { /* Pool for allocating J9MemberNameListNode. */ struct J9Pool *memberNameListNodePool; #endif /* defined(J9VM_OPT_OPENJDK_METHODHANDLE) */ +#if JAVA_SPEC_VERSION >= 22 + omrthread_monitor_t closeScopeMutex; + UDATA closeScopeNotifyCount; +#endif /* JAVA_SPEC_VERSION >= 22 */ } J9JavaVM; #define J9VM_PHASE_STARTUP 1 diff --git a/runtime/vm/AsyncMessageHandler.cpp b/runtime/vm/AsyncMessageHandler.cpp index f886b57e7db..b45b54a2d89 100644 --- a/runtime/vm/AsyncMessageHandler.cpp +++ b/runtime/vm/AsyncMessageHandler.cpp @@ -143,6 +143,7 @@ javaCheckAsyncMessages(J9VMThread *currentThread, UDATA throwExceptions) #if JAVA_SPEC_VERSION >= 22 /* Check for a close scope request. */ if (J9_ARE_ANY_BITS_SET(publicFlags, J9_PUBLIC_FLAGS_CLOSE_SCOPE)) { + bool notifyThreads = false; if (hasMemoryScope(currentThread, currentThread->closeScopeObj)) { if (throwExceptions) { currentThread->currentException = currentThread->scopedError; @@ -150,6 +151,7 @@ javaCheckAsyncMessages(J9VMThread *currentThread, UDATA throwExceptions) currentThread->closeScopeObj = NULL; clearEventFlag(currentThread, J9_PUBLIC_FLAGS_CLOSE_SCOPE); result = J9_CHECK_ASYNC_THROW_EXCEPTION; + notifyThreads = true; } else { VM_VMHelpers::indicateAsyncMessagePending(currentThread); } @@ -157,6 +159,21 @@ javaCheckAsyncMessages(J9VMThread *currentThread, UDATA throwExceptions) currentThread->scopedError = NULL; currentThread->closeScopeObj = NULL; clearEventFlag(currentThread, J9_PUBLIC_FLAGS_CLOSE_SCOPE); + notifyThreads = true; + } + if (notifyThreads) { + J9JavaVM *vm = currentThread->javaVM; + /* Notify all threads that are waiting in ScopedMemoryAccess closeScope0 + * to continue since the MemorySession(s) will no longer be used and it + * is safe to close them. + */ + omrthread_monitor_enter(vm->closeScopeMutex); + Assert_VM_true(vm->closeScopeNotifyCount > 0); + vm->closeScopeNotifyCount -= 1; + if (0 == vm->closeScopeNotifyCount) { + omrthread_monitor_notify_all(vm->closeScopeMutex); + } + omrthread_monitor_exit(vm->closeScopeMutex); } break; } diff --git a/runtime/vm/jvminit.c b/runtime/vm/jvminit.c index 93ef0467763..540cfb1aed4 100644 --- a/runtime/vm/jvminit.c +++ b/runtime/vm/jvminit.c @@ -1025,6 +1025,13 @@ freeJavaVM(J9JavaVM * vm) } #endif /* defined(J9VM_OPT_CRIU_SUPPORT) */ +#if JAVA_SPEC_VERSION >= 22 + if (NULL != vm->closeScopeMutex) { + omrthread_monitor_destroy(vm->closeScopeMutex); + vm->closeScopeMutex = NULL; + } +#endif /* JAVA_SPEC_VERSION >= 22 */ + j9mem_free_memory(vm); if (NULL != tmpLib->self_handle) { diff --git a/runtime/vm/vmthinit.c b/runtime/vm/vmthinit.c index 1ff64e2b4b5..e7ea6fe7db3 100644 --- a/runtime/vm/vmthinit.c +++ b/runtime/vm/vmthinit.c @@ -99,6 +99,10 @@ UDATA initializeVMThreading(J9JavaVM *vm) omrthread_monitor_init_with_name(&vm->delayedLockingOperationsMutex, 0, "Delayed locking operations mutex") || #endif /* defined(J9VM_OPT_CRIU_SUPPORT) */ +#if JAVA_SPEC_VERSION >= 22 + omrthread_monitor_init_with_name(&vm->closeScopeMutex, 0, "ScopedMemoryAccess closeScope0 mutex") || +#endif /* JAVA_SPEC_VERSION >= 22 */ + initializeMonitorTable(vm) ) {