Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spin during VirtualThread MountBegin and UnmountBegin #18439

Merged
merged 1 commit into from
Nov 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
63 changes: 45 additions & 18 deletions runtime/j9vm/javanextvmi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ extern "C" {

#if JAVA_SPEC_VERSION >= 19
extern J9JavaVM *BFUjavaVM;

extern IDATA (*f_threadSleep)(I_64 millis);
#endif /* JAVA_SPEC_VERSION >= 19 */

/* Define for debug
Expand Down Expand Up @@ -328,6 +330,27 @@ virtualThreadMountBegin(JNIEnv *env, jobject thread)
}

enterVThreadTransitionCritical(currentThread, thread);

/* Virtual thread is being mounted but it has been suspended. Spin until the
* virtual thread is resumed. The virtual thread should not be mounted until
* it is resumed.
*/
J9JavaVM *vm = currentThread->javaVM;
J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
threadObj = J9_JNI_UNWRAP_REFERENCE(thread);
while (0 != J9OBJECT_U32_LOAD(currentThread, threadObj, vm->isSuspendedInternalOffset)) {
exitVThreadTransitionCritical(currentThread, threadObj);
vmFuncs->internalReleaseVMAccess(currentThread);
/* Spin is used instead of the halt flag; otherwise, the carrier thread will
* show as suspended.
*
* TODO: Dynamically increase the sleep time to a bounded maximum.
*/
f_threadSleep(10);
vmFuncs->internalAcquireVMAccess(currentThread);
enterVThreadTransitionCritical(currentThread, thread);
threadObj = J9_JNI_UNWRAP_REFERENCE(thread);
}
}

/* Caller must have VMAccess. */
Expand All @@ -354,15 +377,6 @@ virtualThreadMountEnd(JNIEnv *env, jobject thread)
J9VMJDKINTERNALVMCONTINUATION_VMREF(currentThread, continuationObj));
}

/* Virtual thread is being mounted but it has been suspended. Thus,
* set J9_PUBLIC_FLAGS_HALT_THREAD_JAVA_SUSPEND flag. At this
* point, virtual thread object is stored in targetThread->threadObject.
*/
if (0 != J9OBJECT_U32_LOAD(currentThread, threadObj, vm->isSuspendedInternalOffset)) {
Assert_SC_true(threadObj == currentThread->threadObject);
vm->internalVMFunctions->setHaltFlag(currentThread, J9_PUBLIC_FLAGS_HALT_THREAD_JAVA_SUSPEND);
}

/* Allow thread to be inspected again. */
exitVThreadTransitionCritical(currentThread, threadObj);

Expand Down Expand Up @@ -396,6 +410,28 @@ virtualThreadUnmountBegin(JNIEnv *env, jobject thread)

enterVThreadTransitionCritical(currentThread, thread);
VM_VMHelpers::virtualThreadHideFrames(currentThread, JNI_TRUE);

J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
j9object_t carrierThreadObject = currentThread->carrierThreadObject;
threadObj = J9_JNI_UNWRAP_REFERENCE(thread);
/* Virtual thread is being umounted. If its carrier thread is suspended, spin until
* the carrier thread is resumed. The carrier thread should not be mounted until it
* is resumed.
*/
while (0 != J9OBJECT_U32_LOAD(currentThread, carrierThreadObject, vm->isSuspendedInternalOffset)) {
exitVThreadTransitionCritical(currentThread, threadObj);
vmFuncs->internalReleaseVMAccess(currentThread);
/* Spin is used instead of the halt flag; otherwise, the virtual thread will
* show as suspended.
*
* TODO: Dynamically increase the sleep time to a bounded maximum.
*/
f_threadSleep(10);
babsingh marked this conversation as resolved.
Show resolved Hide resolved
vmFuncs->internalAcquireVMAccess(currentThread);
enterVThreadTransitionCritical(currentThread, thread);
carrierThreadObject = currentThread->carrierThreadObject;
threadObj = J9_JNI_UNWRAP_REFERENCE(thread);
}
}

/* Caller must have VMAccess. */
Expand Down Expand Up @@ -429,15 +465,6 @@ virtualThreadUnmountEnd(JNIEnv *env, jobject thread)
vmFuncs->freeTLS(currentThread, threadObj);
}

j9object_t carrierThreadObject = currentThread->carrierThreadObject;
/* The J9_PUBLIC_FLAGS_HALT_THREAD_JAVA_SUSPEND will be set for the virtual
* thread's carrier thread if it was suspended while the virtual thread was mounted.
*/
if (0 != J9OBJECT_U32_LOAD(currentThread, carrierThreadObject, vm->isSuspendedInternalOffset)) {
Assert_SC_true((currentThread->threadObject == carrierThreadObject) && (NULL == currentThread->currentContinuation));
vmFuncs->setHaltFlag(currentThread, J9_PUBLIC_FLAGS_HALT_THREAD_JAVA_SUSPEND);
}

/* Allow thread to be inspected again. */
exitVThreadTransitionCritical(currentThread, threadObj);
}
Expand Down
8 changes: 6 additions & 2 deletions runtime/j9vm/jvm.c
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ typedef IDATA (*MonitorDestroy)(omrthread_monitor_t monitor);
typedef IDATA (* ThreadLibControl)(const char * key, UDATA value);
typedef IDATA (*SetCategory)(omrthread_t thread, UDATA category, UDATA type);
typedef IDATA (*LibEnableCPUMonitor)(omrthread_t thread);
typedef IDATA (*ThreadSleep)(I_64 millis);

typedef I_32 (*PortInitLibrary)(J9PortLibrary *portLib, J9PortLibraryVersion *version, UDATA size);
typedef UDATA (*PortGetSize)(struct J9PortLibraryVersion *version);
Expand Down Expand Up @@ -260,6 +261,7 @@ static pNewStringPlatform globalNewStringPlatform;
static p_a2e_vsprintf global_a2e_vsprintf;
#endif

ThreadSleep f_threadSleep;
static ThreadGlobal f_threadGlobal;
static ThreadAttachEx f_threadAttachEx;
static ThreadDetach f_threadDetach;
Expand Down Expand Up @@ -1015,8 +1017,9 @@ preloadLibraries(void)
f_threadLibControl = (ThreadLibControl) GetProcAddress (threadDLL, (LPCSTR) "omrthread_lib_control");
f_setCategory = (SetCategory) GetProcAddress (threadDLL, (LPCSTR) "omrthread_set_category");
f_libEnableCPUMonitor = (LibEnableCPUMonitor) GetProcAddress (threadDLL, (LPCSTR) "omrthread_lib_enable_cpu_monitor");
f_threadSleep = (ThreadSleep) GetProcAddress (threadDLL, (LPCSTR) "omrthread_sleep");
if (!f_threadGlobal || !f_threadAttachEx || !f_threadDetach || !f_monitorEnter || !f_monitorExit || !f_monitorInit
|| !f_monitorDestroy || !f_threadLibControl || !f_setCategory || !f_libEnableCPUMonitor
|| !f_monitorDestroy || !f_threadLibControl || !f_setCategory || !f_libEnableCPUMonitor || !f_threadSleep
) {
FreeLibrary(vmDLL);
FreeLibrary(threadDLL);
Expand Down Expand Up @@ -1442,8 +1445,9 @@ preloadLibraries(void)
f_threadLibControl = (ThreadLibControl) dlsym (threadDLL, "omrthread_lib_control");
f_setCategory = (SetCategory) dlsym (threadDLL, "omrthread_set_category");
f_libEnableCPUMonitor = (LibEnableCPUMonitor) dlsym (threadDLL, "omrthread_lib_enable_cpu_monitor");
f_threadSleep = (ThreadSleep) dlsym (threadDLL, "omrthread_sleep");
if (!f_threadGlobal || !f_threadAttachEx || !f_threadDetach || !f_monitorEnter || !f_monitorExit || !f_monitorInit
|| !f_monitorDestroy || !f_threadLibControl || !f_setCategory || !f_libEnableCPUMonitor
|| !f_monitorDestroy || !f_threadLibControl || !f_setCategory || !f_libEnableCPUMonitor || !f_threadSleep
) {
dlclose(vmDLL);
#ifdef J9ZOS390
Expand Down
2 changes: 1 addition & 1 deletion runtime/jvmti/jvmtiThread.c
Original file line number Diff line number Diff line change
Expand Up @@ -1326,7 +1326,7 @@ jvmtiSuspendResumeCallBack(J9VMThread *vmThread, J9MM_IterateObjectDescriptor *o
{
j9object_t continuationObj = object->object;
j9object_t vthread = J9VMJDKINTERNALVMCONTINUATION_VTHREAD(vmThread, continuationObj);
ContinuationState continuationState = J9VMJDKINTERNALVMCONTINUATION_STATE(vmThread, continuationObj);;
ContinuationState continuationState = J9VMJDKINTERNALVMCONTINUATION_STATE(vmThread, continuationObj);

if ((NULL != vthread) && J9_ARE_NO_BITS_SET(continuationState, J9_GC_CONTINUATION_STATE_LAST_UNMOUNT)) {
jvmtiVThreadCallBackData *data = (jvmtiVThreadCallBackData*)userData;
Expand Down