Skip to content

Commit 5f3d445

Browse files
committed
Fix interruptLock deadlock and numerous other issues.
1 parent f7753af commit 5f3d445

19 files changed

+444
-96
lines changed

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/JavaLangSubstitutions.java

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
import com.oracle.svm.core.monitor.MonitorSupport;
7272
import com.oracle.svm.core.snippets.KnownIntrinsics;
7373
import com.oracle.svm.core.snippets.SubstrateForeignCallTarget;
74+
import com.oracle.svm.core.thread.VirtualThreads;
7475
import com.oracle.svm.core.util.VMError;
7576

7677
import jdk.vm.ci.meta.MetaAccessProvider;
@@ -104,12 +105,28 @@ private void waitSubst(long timeoutMillis) throws InterruptedException {
104105
MonitorSupport.singleton().wait(this, timeoutMillis);
105106
}
106107

108+
/**
109+
* Our monitors do not pin virtual threads, so we must avoid {@code jdk.internal.misc.Blocker}
110+
* which expects and asserts that the virtual thread is pinned.
111+
*/
107112
@Substitute
108-
@TargetElement(name = "wait0", onlyWith = JDK19OrLater.class)
109-
private void waitSubstLoom(long timeoutMillis) throws InterruptedException {
110-
MonitorSupport.singleton().wait(this, timeoutMillis);
113+
@TargetElement(name = "wait", onlyWith = JDK19OrLater.class)
114+
private void waitSubstJDK19(long timeoutMillis) throws InterruptedException {
115+
try {
116+
MonitorSupport.singleton().wait(this, timeoutMillis);
117+
} catch (InterruptedException e) {
118+
Thread thread = Thread.currentThread();
119+
if (VirtualThreads.isSupported() && VirtualThreads.singleton().isVirtual(thread)) {
120+
VirtualThreads.singleton().getAndClearInterrupt(thread);
121+
}
122+
throw e;
123+
}
111124
}
112125

126+
@Delete
127+
@TargetElement(onlyWith = JDK19OrLater.class)
128+
private native void wait0(long timeoutMillis);
129+
113130
@Substitute
114131
@TargetElement(name = "notify")
115132
private void notifySubst() {

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/RecomputedFields.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
import org.graalvm.nativeimage.hosted.Feature;
4949
import org.graalvm.nativeimage.impl.RuntimeClassInitializationSupport;
5050

51+
import com.oracle.svm.core.StaticFieldsSupport;
5152
import com.oracle.svm.core.SubstrateUtil;
5253
import com.oracle.svm.core.annotate.Alias;
5354
import com.oracle.svm.core.annotate.AutomaticFeature;
@@ -332,6 +333,19 @@ public static int getCommonPoolParallelism() {
332333
@TargetElement(onlyWith = JDK17OrEarlier.class)//
333334
static int COMMON_PARALLELISM;
334335

336+
@Alias @TargetElement(onlyWith = JDK19OrLater.class) //
337+
private static Unsafe U;
338+
339+
@Alias @TargetElement(onlyWith = JDK19OrLater.class) //
340+
private static long POOLIDS;
341+
342+
@Substitute
343+
@TargetElement(onlyWith = JDK19OrLater.class) //
344+
private static int getAndAddPoolIds(int x) {
345+
// Original method wrongly uses ForkJoinPool.class instead of calling U.staticFieldBase()
346+
return U.getAndAddInt(StaticFieldsSupport.getStaticPrimitiveFields(), POOLIDS, x);
347+
}
348+
335349
@Alias //
336350
Target_java_util_concurrent_ForkJoinPool(byte forCommonPoolOnly) {
337351
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/StackTraceUtils.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -138,10 +138,8 @@ public static boolean shouldShowFrame(FrameInfoQueryResult frameInfo, boolean sh
138138
}
139139

140140
if (LoomSupport.isEnabled() && clazz == Target_jdk_internal_vm_Continuation.class) {
141-
// Skip intrinsics in JDK
142-
if ("enterSpecial".equals(frameInfo.getSourceMethodName())) {
143-
return false;
144-
} else if ("doYield".equals(frameInfo.getSourceMethodName())) {
141+
String name = frameInfo.getSourceMethodName();
142+
if ("enter0".equals(name) || "enterSpecial".equals(name)) {
145143
return false;
146144
}
147145
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/Target_java_lang_StackWalker.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ private <T> T walk(Function<? super Stream<StackFrame>, ? extends T> function) {
143143
Target_jdk_internal_vm_ContinuationScope delimitationScope = this.contScope != null ? this.contScope : Target_java_lang_VirtualThread.continuationScope();
144144
Target_jdk_internal_vm_Continuation topContinuation = Target_jdk_internal_vm_Continuation.getCurrentContinuation(delimitationScope);
145145
if (topContinuation != null) {
146-
JavaStackWalker.initWalk(walk, sp, LoomSupport.getBaseSP(topContinuation));
146+
JavaStackWalker.initWalk(walk, sp, LoomSupport.getInternalContinuation(topContinuation).getBaseSP());
147147
} else {
148148
// the delimitation scope is not present in current continuation chain or null
149149
JavaStackWalker.initWalk(walk, sp);

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MonitorSupport.java

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.graalvm.nativeimage.ImageSingletons;
2929

3030
import com.oracle.svm.core.annotate.Uninterruptible;
31+
import com.oracle.svm.core.thread.ThreadStatus;
3132

3233
/**
3334
* This interface provides functions related to monitor operations (the Java "synchronized" keyword
@@ -101,14 +102,14 @@ public final void wait(Object obj, long timeoutMillis) throws InterruptedExcepti
101102
public abstract void notify(Object obj, boolean notifyAll);
102103

103104
/**
104-
* Called from {@code Unsafe.park} when changing the current thread's state before parking the
105-
* thread. When the thread is parked due to a monitor operation, we need to alter the new thread
106-
* state so {@link Thread#getState()} gives the expected result.
105+
* Gets a {@link ThreadStatus} for the given parking thread, determining whether it parks
106+
* because of a monitor, and if so, returning monitor-specific status codes such as
107+
* {@link ThreadStatus#BLOCKED_ON_MONITOR_ENTER} or {@link ThreadStatus#IN_OBJECT_WAIT_TIMED},
108+
* or if not, {@link ThreadStatus#PARKED} or {@link ThreadStatus#PARKED_TIMED}.
107109
*
108-
* Note that the thread state is set only while the thread is parked, but if the thread is
109-
* spuriously unparked, the thread's state briefly changes to running until it parks again. This
110-
* is a difference to other VMs which remain in the blocked/waiting state until the monitor has
111-
* been successfully acquired.
110+
* Note that when a thread is spuriously unparked, the thread's state briefly changes to running
111+
* until it parks again. This is a difference to other VMs which remain in the blocked/waiting
112+
* state until the monitor has been successfully acquired.
112113
*/
113-
public abstract int maybeAdjustNewParkStatus(int status);
114+
public abstract int getParkedThreadStatus(Thread thread, boolean timed);
114115
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/MultiThreadedMonitorSupport.java

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -182,19 +182,16 @@ public class MultiThreadedMonitorSupport extends MonitorSupport {
182182
private final ReentrantLock additionalMonitorsLock = new ReentrantLock();
183183

184184
@Override
185-
public int maybeAdjustNewParkStatus(int status) {
186-
Object blocker = LockSupport.getBlocker(Thread.currentThread());
185+
public int getParkedThreadStatus(Thread thread, boolean timed) {
186+
Object blocker = LockSupport.getBlocker(thread);
187187
if (blocker instanceof JavaMonitorConditionObject) {
188188
// Blocked on one of the condition objects that implement Object.wait()
189-
if (status == ThreadStatus.PARKED_TIMED) {
190-
return ThreadStatus.IN_OBJECT_WAIT_TIMED;
191-
}
192-
return ThreadStatus.IN_OBJECT_WAIT;
189+
return timed ? ThreadStatus.IN_OBJECT_WAIT_TIMED : ThreadStatus.IN_OBJECT_WAIT;
193190
} else if (blocker instanceof JavaMonitor) {
194191
// Blocked directly on the lock
195192
return ThreadStatus.BLOCKED_ON_MONITOR_ENTER;
196193
}
197-
return status;
194+
return timed ? ThreadStatus.PARKED_TIMED : ThreadStatus.PARKED;
198195
}
199196

200197
@SubstrateForeignCallTarget(stubCallingConvention = false)

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/monitor/SingleThreadedMonitorSupport.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
package com.oracle.svm.core.monitor;
2626

2727
import com.oracle.svm.core.annotate.Uninterruptible;
28+
import com.oracle.svm.core.thread.ThreadStatus;
2829

2930
/**
3031
* Without support for threads, there is no need for any monitor operations.
@@ -84,7 +85,7 @@ public void notify(Object obj, boolean notifyAll) {
8485
}
8586

8687
@Override
87-
public int maybeAdjustNewParkStatus(int status) {
88-
return status;
88+
public int getParkedThreadStatus(Thread thread, boolean timed) {
89+
return timed ? ThreadStatus.PARKED_TIMED : ThreadStatus.PARKED;
8990
}
9091
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaLangThreadGroupSubstitutions.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,6 @@ public Object compute(MetaAccessProvider metaAccess, ResolvedJavaField original,
162162
return ThreadStatus.NEW;
163163
}
164164
}
165-
166165
}
167166

168167
@Platforms(Platform.HOSTED_ONLY.class)

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/JavaThreads.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ static void initializeNewThread(
265265
}
266266
tjlt.name = name;
267267

268-
final Thread parent = PlatformThreads.currentThread.get();
268+
final Thread parent = Thread.currentThread();
269269
final ThreadGroup group = ((groupArg != null) ? groupArg : parent.getThreadGroup());
270270

271271
int priority;
@@ -366,4 +366,12 @@ public static Object getCurrentThreadLockHelper() {
366366
}
367367
return PlatformThreads.lockHelper.get();
368368
}
369+
370+
public static void blockedOn(Target_sun_nio_ch_Interruptible b) {
371+
if (supportsVirtual() && isVirtual(Thread.currentThread())) {
372+
VirtualThreads.singleton().blockedOn(b);
373+
} else {
374+
PlatformThreads.blockedOn(b);
375+
}
376+
}
369377
}

substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/thread/LoomSupport.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929

3030
import org.graalvm.compiler.api.replacements.Fold;
3131
import org.graalvm.compiler.serviceprovider.JavaVersionUtil;
32-
import org.graalvm.word.Pointer;
3332

3433
public final class LoomSupport {
3534
private static final boolean isEnabled;
@@ -55,8 +54,8 @@ public static boolean isEnabled() {
5554
static final int FREEZE_PINNED_CS = 2; // critical section
5655
static final int FREEZE_PINNED_NATIVE = 3;
5756

58-
public static Pointer getBaseSP(Target_jdk_internal_vm_Continuation cont) {
59-
return cont.internal.getBaseSP();
57+
public static Continuation getInternalContinuation(Target_jdk_internal_vm_Continuation cont) {
58+
return cont.internal;
6059
}
6160

6261
private LoomSupport() {

0 commit comments

Comments
 (0)