Skip to content

Commit 9bb3c2d

Browse files
authored
Merge pull request eclipse-openj9#21355 from tajila/vt
Fix issue with waiting vthreads
2 parents eac2531 + d2811ca commit 9bb3c2d

File tree

4 files changed

+102
-28
lines changed

4 files changed

+102
-28
lines changed

runtime/oti/ContinuationHelpers.hpp

+33
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,39 @@ class VM_ContinuationHelpers {
290290
&& (0 == vmThread->continuationPinCount)
291291
&& (0 == vmThread->callOutCount));
292292
}
293+
294+
/**
295+
* Remove a continuation from the provided list.
296+
*
297+
* @param[in] list the list from which the continuation should be removed
298+
* @param[in] continuation the continuation to be removed
299+
*
300+
* @return true if the continuation is found and removed from the list, otherwise false
301+
*/
302+
static bool
303+
removeContinuationFromList(J9VMContinuation **list, J9VMContinuation *continuation)
304+
{
305+
bool foundInList = false;
306+
J9VMContinuation *previous = NULL;
307+
J9VMContinuation *current = *list;
308+
309+
while (NULL != current) {
310+
if (continuation == current) {
311+
foundInList = true;
312+
if (NULL == previous) {
313+
*list = current->nextWaitingContinuation;
314+
} else {
315+
previous->nextWaitingContinuation = current->nextWaitingContinuation;
316+
}
317+
current->nextWaitingContinuation = NULL;
318+
break;
319+
}
320+
previous = current;
321+
current = current->nextWaitingContinuation;
322+
}
323+
324+
return foundInList;
325+
}
293326
#endif /* JAVA_SPEC_VERSION >= 24 */
294327
};
295328

runtime/oti/j9nonbuilder.h

+1
Original file line numberDiff line numberDiff line change
@@ -5462,6 +5462,7 @@ typedef struct J9VMContinuation {
54625462
struct J9MonitorEnterRecord* jniMonitorEnterRecords;
54635463
j9object_t vthread;
54645464
struct J9VMContinuation* nextWaitingContinuation;
5465+
struct J9ObjectMonitor* objectWaitMonitor;
54655466
#endif /* JAVA_SPEC_VERSION >= 24 */
54665467
} J9VMContinuation;
54675468
#endif /* JAVA_SPEC_VERSION >= 19 */

runtime/vm/BytecodeInterpreter.hpp

+5-5
Original file line numberDiff line numberDiff line change
@@ -2952,14 +2952,14 @@ class INTERPRETER_CLASS
29522952
J9VMJAVALANGVIRTUALTHREAD_SET_NOTIFIED(_currentThread, head->vthread, JNI_TRUE);
29532953
} else {
29542954
J9VMContinuation *next = head;
2955-
J9VMJAVALANGVIRTUALTHREAD_SET_ONWAITINGLIST(_currentThread, head->vthread, JNI_TRUE);
2956-
J9VMJAVALANGVIRTUALTHREAD_SET_NOTIFIED(_currentThread, head->vthread, JNI_TRUE);
2957-
while (NULL != next->nextWaitingContinuation) {
2955+
J9VMContinuation *prev = NULL;
2956+
while (NULL != next) {
29582957
J9VMJAVALANGVIRTUALTHREAD_SET_ONWAITINGLIST(_currentThread, next->vthread, JNI_TRUE);
29592958
J9VMJAVALANGVIRTUALTHREAD_SET_NOTIFIED(_currentThread, next->vthread, JNI_TRUE);
2959+
prev = next;
29602960
next = next->nextWaitingContinuation;
29612961
}
2962-
next->nextWaitingContinuation = _vm->blockedContinuations;
2962+
prev->nextWaitingContinuation = _vm->blockedContinuations;
29632963
_vm->blockedContinuations = head;
29642964
objectMonitor->waitingContinuations = NULL;
29652965
}
@@ -5174,7 +5174,7 @@ class INTERPRETER_CLASS
51745174
VMStructHasBeenUpdated(REGISTER_ARGS);
51755175
if (J9_OBJECT_MONITOR_OOM != result) {
51765176
restoreInternalNativeStackFrame(REGISTER_ARGS);
5177-
/* Handle the virutal thread Object.wait call. */
5177+
/* Handle the virtual thread Object.wait call. */
51785178
J9VMJAVALANGVIRTUALTHREAD_SET_NOTIFIED(_currentThread, _currentThread->threadObject, JNI_FALSE);
51795179
rc = yieldPinnedContinuation(REGISTER_ARGS, newState, J9VM_CONTINUATION_RETURN_FROM_OBJECT_WAIT);
51805180
} else {

runtime/vm/ContinuationHelpers.cpp

+63-23
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ synchronizeWithConcurrentGCScan(J9VMThread *currentThread, j9object_t continuati
220220
BOOLEAN
221221
enterContinuation(J9VMThread *currentThread, j9object_t continuationObject)
222222
{
223+
J9JavaVM *vm = currentThread->javaVM;
223224
BOOLEAN result = TRUE;
224225
J9VMContinuation *continuation = J9VMJDKINTERNALVMCONTINUATION_VMREF(currentThread, continuationObject);
225226
ContinuationState volatile *continuationStatePtr = VM_ContinuationHelpers::getContinuationStateAddress(currentThread, continuationObject);
@@ -232,7 +233,7 @@ enterContinuation(J9VMThread *currentThread, j9object_t continuationObject)
232233
/* Directly return result if the create code failed, exception is already set. */
233234
return result;
234235
}
235-
currentThread->javaVM->memoryManagerFunctions->continuationObjectStarted(currentThread, continuationObject);
236+
vm->memoryManagerFunctions->continuationObjectStarted(currentThread, continuationObject);
236237

237238
continuation = J9VMJDKINTERNALVMCONTINUATION_VMREF(currentThread, continuationObject);
238239
#if JAVA_SPEC_VERSION >= 24
@@ -241,6 +242,33 @@ enterContinuation(J9VMThread *currentThread, j9object_t continuationObject)
241242
}
242243
Assert_VM_notNull(continuation);
243244

245+
#if JAVA_SPEC_VERSION >= 24
246+
if (NULL != continuation->nextWaitingContinuation) {
247+
/* Continuation is still in a blocked list. This can happen with TIMED_WAIT.
248+
* It must be removed from the waiting list.
249+
*/
250+
bool foundInBlockedContinuationList = false;
251+
bool foundInMonitorList = false;
252+
253+
omrthread_monitor_enter(vm->blockedVirtualThreadsMutex);
254+
255+
foundInBlockedContinuationList = VM_ContinuationHelpers::removeContinuationFromList(
256+
&vm->blockedContinuations, continuation);
257+
258+
foundInMonitorList = VM_ContinuationHelpers::removeContinuationFromList(
259+
&continuation->objectWaitMonitor->waitingContinuations, continuation);
260+
261+
omrthread_monitor_exit(vm->blockedVirtualThreadsMutex);
262+
263+
Assert_VM_true(foundInMonitorList || foundInMonitorList);
264+
265+
/* Virtual can only be in one list at a time. */
266+
Assert_VM_false(foundInBlockedContinuationList && foundInMonitorList);
267+
268+
continuation->objectWaitMonitor = NULL;
269+
}
270+
#endif /* JAVA_SPEC_VERSION >= 24 */
271+
244272
/* let GC know we are mounting, so they don't need to scan us, or if there is already ongoing scan wait till it's complete. */
245273
continuationObject = synchronizeWithConcurrentGCScan(currentThread, continuationObject, continuationStatePtr);
246274

@@ -816,6 +844,7 @@ preparePinnedVirtualThreadForUnmount(J9VMThread *currentThread, j9object_t syncO
816844
j9objectmonitor_t lock = 0;
817845
j9object_t continuationObj = NULL;
818846
UDATA monitorCount = 0;
847+
J9JavaVM *vm = currentThread->javaVM;
819848

820849
if (NULL != syncObj) {
821850
enterVThreadTransitionCritical(currentThread, (jobject)&currentThread->threadObject);
@@ -829,7 +858,7 @@ preparePinnedVirtualThreadForUnmount(J9VMThread *currentThread, j9object_t syncO
829858

830859
if (syncObj != object) {
831860
if (!LN_HAS_LOCKWORD(currentThread, object)) {
832-
objectMonitor = monitorTablePeek(currentThread->javaVM, object);
861+
objectMonitor = monitorTablePeek(vm, object);
833862
if (NULL != objectMonitor) {
834863
lock = J9_LOAD_LOCKWORD(currentThread, &objectMonitor->alternateLockword);
835864
} else {
@@ -863,7 +892,7 @@ preparePinnedVirtualThreadForUnmount(J9VMThread *currentThread, j9object_t syncO
863892

864893
if (syncObj != object) {
865894
if (!LN_HAS_LOCKWORD(currentThread, object)) {
866-
objectMonitor = monitorTablePeek(currentThread->javaVM, object);
895+
objectMonitor = monitorTablePeek(vm, object);
867896
if (NULL != objectMonitor) {
868897
lock = J9_LOAD_LOCKWORD(currentThread, &objectMonitor->alternateLockword);
869898
} else {
@@ -892,7 +921,7 @@ preparePinnedVirtualThreadForUnmount(J9VMThread *currentThread, j9object_t syncO
892921

893922
if (NULL != syncObj) {
894923
if (!LN_HAS_LOCKWORD(currentThread, syncObj)) {
895-
syncObjectMonitor = monitorTablePeek(currentThread->javaVM, syncObj);
924+
syncObjectMonitor = monitorTablePeek(vm, syncObj);
896925
if (NULL != syncObjectMonitor) {
897926
lock = J9_LOAD_LOCKWORD(currentThread, &syncObjectMonitor->alternateLockword);
898927
} else {
@@ -930,10 +959,11 @@ preparePinnedVirtualThreadForUnmount(J9VMThread *currentThread, j9object_t syncO
930959

931960
/* Add Continuation struct to the monitor's waiting list. */
932961
omrthread_monitor_exit(monitor);
933-
omrthread_monitor_enter(currentThread->javaVM->blockedVirtualThreadsMutex);
962+
omrthread_monitor_enter(vm->blockedVirtualThreadsMutex);
934963
currentThread->currentContinuation->nextWaitingContinuation = syncObjectMonitor->waitingContinuations;
935964
syncObjectMonitor->waitingContinuations = currentThread->currentContinuation;
936-
omrthread_monitor_exit(currentThread->javaVM->blockedVirtualThreadsMutex);
965+
currentThread->currentContinuation->objectWaitMonitor = syncObjectMonitor;
966+
omrthread_monitor_exit(vm->blockedVirtualThreadsMutex);
937967
} else {
938968
syncObjectMonitor->virtualThreadWaitCount += 1;
939969
}
@@ -971,33 +1001,32 @@ takeVirtualThreadListToUnblock(J9VMThread *currentThread)
9711001
while (NULL == unblockedList) {
9721002
if (NULL != vm->blockedContinuations) {
9731003
restart:
974-
J9VMContinuation *listHead = vm->blockedContinuations;
1004+
J9VMContinuation *previous = NULL;
1005+
J9VMContinuation *current = vm->blockedContinuations;
9751006
J9VMContinuation *next = NULL;
976-
vm->blockedContinuations = NULL;
977-
while (NULL != listHead) {
1007+
while (NULL != current) {
9781008
bool unblocked = false;
979-
next = listHead->nextWaitingContinuation;
980-
U_32 state = J9VMJAVALANGVIRTUALTHREAD_STATE(currentThread, listHead->vthread);
1009+
U_32 state = J9VMJAVALANGVIRTUALTHREAD_STATE(currentThread, current->vthread);
1010+
next = current->nextWaitingContinuation;
9811011
/* Skip vthreads that are still in transition. */
9821012
switch (state) {
9831013
case JAVA_LANG_VIRTUALTHREAD_BLOCKING:
9841014
case JAVA_LANG_VIRTUALTHREAD_WAITING:
9851015
case JAVA_LANG_VIRTUALTHREAD_TIMED_WAITING:
986-
listHead->nextWaitingContinuation = vm->blockedContinuations;
987-
vm->blockedContinuations = listHead;
988-
listHead = next;
1016+
previous = current;
1017+
current = next;
9891018
continue;
9901019
case JAVA_LANG_VIRTUALTHREAD_WAIT:
9911020
case JAVA_LANG_VIRTUALTHREAD_TIMED_WAIT:
992-
J9VMJAVALANGVIRTUALTHREAD_SET_STATE(currentThread, listHead->vthread, JAVA_LANG_VIRTUALTHREAD_BLOCKED);
1021+
J9VMJAVALANGVIRTUALTHREAD_SET_STATE(currentThread, current->vthread, JAVA_LANG_VIRTUALTHREAD_BLOCKED);
9931022
/* FALLTHROUGH */
9941023
default:
9951024
break;
9961025
}
997-
if (J9VMJAVALANGVIRTUALTHREAD_ONWAITINGLIST(currentThread, listHead->vthread)) {
1026+
if (J9VMJAVALANGVIRTUALTHREAD_ONWAITINGLIST(currentThread, current->vthread)) {
9981027
unblocked = true;
9991028
} else {
1000-
j9object_t continuationObj = J9VMJAVALANGVIRTUALTHREAD_CONT(currentThread, listHead->vthread);
1029+
j9object_t continuationObj = J9VMJAVALANGVIRTUALTHREAD_CONT(currentThread, current->vthread);
10011030
j9object_t syncObject = J9VMJDKINTERNALVMCONTINUATION_BLOCKER(currentThread, continuationObj);
10021031
J9ObjectMonitor *syncObjectMonitor = NULL;
10031032
j9objectmonitor_t lock = 0;
@@ -1016,18 +1045,29 @@ takeVirtualThreadListToUnblock(J9VMThread *currentThread)
10161045
if (syncObjectMonitor->virtualThreadWaitCount >= 1) {
10171046
syncObjectMonitor->virtualThreadWaitCount -= 1;
10181047
}
1019-
J9VMJAVALANGVIRTUALTHREAD_SET_ONWAITINGLIST(currentThread, listHead->vthread, JNI_TRUE);
1048+
J9VMJAVALANGVIRTUALTHREAD_SET_ONWAITINGLIST(currentThread, current->vthread, JNI_TRUE);
10201049
}
10211050
}
10221051

10231052
if (unblocked) {
1024-
J9VMJAVALANGVIRTUALTHREAD_SET_NEXT(currentThread, listHead->vthread, unblockedList);
1025-
unblockedList = listHead->vthread;
1053+
/* Add to Java unblock list. */
1054+
J9VMJAVALANGVIRTUALTHREAD_SET_NEXT(currentThread, current->vthread, unblockedList);
1055+
unblockedList = current->vthread;
1056+
1057+
/* Remove from native blocking list. */
1058+
current->nextWaitingContinuation = NULL;
1059+
1060+
if (NULL == previous) {
1061+
vm->blockedContinuations = next;
1062+
} else {
1063+
previous->nextWaitingContinuation = next;
1064+
}
10261065
} else {
1027-
listHead->nextWaitingContinuation = vm->blockedContinuations;
1028-
vm->blockedContinuations = listHead;
1066+
/* Keep in native blocking list. */
1067+
previous = current;
10291068
}
1030-
listHead = next;
1069+
1070+
current = next;
10311071
}
10321072
if (NULL == unblockedList) {
10331073
vmFuncs->internalExitVMToJNI(currentThread);

0 commit comments

Comments
 (0)