Skip to content

Commit 883ee06

Browse files
committed
[GR-61335] [GR-61393] Fix missing synchronization in statistics listener. Fix transient safepoint poll failure.
PullRequest: graal/19792
2 parents 3819778 + 18cba17 commit 883ee06

File tree

7 files changed

+70
-30
lines changed

7 files changed

+70
-30
lines changed

substratevm/src/com.oracle.svm.truffle/src/com/oracle/svm/truffle/api/SubstrateThreadLocalHandshake.java

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@
5252
import com.oracle.svm.core.threadlocal.FastThreadLocalInt;
5353
import com.oracle.svm.core.threadlocal.FastThreadLocalObject;
5454
import com.oracle.svm.core.util.VMError;
55-
import com.oracle.truffle.api.CompilerDirectives;
5655
import com.oracle.truffle.api.impl.ThreadLocalHandshake;
5756
import com.oracle.truffle.api.nodes.Node;
5857

@@ -140,12 +139,7 @@ public TruffleSafepointImpl getCurrent() {
140139
if (SubstrateUtil.HOSTED) {
141140
return HOSTED_STATE.get();
142141
} else {
143-
TruffleSafepointImpl state = STATE.get();
144-
if (state == null) {
145-
throw CompilerDirectives.shouldNotReachHere("Thread local handshake is not initialized for this thread. " +
146-
"Did you call getCurrent() outside while a polyglot context not entered?");
147-
}
148-
return state;
142+
return STATE.get();
149143
}
150144
}
151145

truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/TruffleSafepointTest.java

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1703,6 +1703,56 @@ public boolean call(TestSetup s, TestRootNode node) {
17031703
}
17041704
}
17051705

1706+
/*
1707+
* Test for GR-61393. We enter and schedule a thread local action on the current thread. Then we
1708+
* spawn a thread that polls safepoints which is not entered. So TruffleSafepoint.getCurrent()
1709+
* is not initialized. We should still be able to poll safepoints there. In the default
1710+
* handshake implementation this did fail because DefaultThreadLocalHandshake.PENDING_COUNT is
1711+
* global.
1712+
*/
1713+
@Test
1714+
public void testTruffleSafepointNotEnteredThread() throws Throwable {
1715+
try (Context c = createTestContext()) {
1716+
c.enter();
1717+
c.initialize(ProxyLanguage.ID);
1718+
Env env = LanguageContext.get(null).getEnv();
1719+
1720+
env.submitThreadLocal(null, new ThreadLocalAction(false, false) {
1721+
@Override
1722+
protected void perform(Access access) {
1723+
// don't ever process this action
1724+
}
1725+
});
1726+
1727+
AtomicReference<Throwable> e = new AtomicReference<>();
1728+
Thread t = new Thread(() -> {
1729+
try {
1730+
AbstractPolyglotTest.assertFails(() -> TruffleSafepoint.getCurrent(), Throwable.class, (ex) -> {
1731+
/*
1732+
* If we build this on an older SVM version (23.1) then we might still get
1733+
* an AssertionError here.
1734+
*/
1735+
assertTrue(ex instanceof AssertionError || ex instanceof IllegalStateException);
1736+
});
1737+
1738+
// no exception, just ignored
1739+
TruffleSafepoint.poll(null);
1740+
TruffleSafepoint.pollHere(null);
1741+
} catch (Throwable error) {
1742+
e.set(error);
1743+
}
1744+
});
1745+
1746+
t.start();
1747+
t.join();
1748+
1749+
Throwable error = e.get();
1750+
if (error != null) {
1751+
throw error;
1752+
}
1753+
}
1754+
}
1755+
17061756
@Ignore("GR-55104: transiently hangs")
17071757
@Test
17081758
public void testDeadlockDueToTooFewCarrierThreads() {

truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/TruffleSafepoint.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,8 @@ protected TruffleSafepoint(EngineSupport support) {
124124
* Guest language exceptions may be thrown by this method. If
125125
* {@link #setAllowSideEffects(boolean) side-effects} are allowed then also guest language
126126
* exceptions may be thrown. Otherwise only internal or {@link ThreadDeath thread-death}
127-
* exceptions may be thrown. This method is safe to be used on compiled code paths.
127+
* exceptions may be thrown. This method is safe to be used on compiled code paths. Polling may
128+
* be performed on threads without entered polyglot context, polls are ignored there.
128129
* <p>
129130
* Example usage with an unbounded loop sum behind a {@link TruffleBoundary}.
130131
*
@@ -238,7 +239,7 @@ public static void pollHere(Node location) {
238239
* TruffleSafepoint sp = TruffleSafepoint.getCurrent();
239240
* sp.setBlocked(location, Interrupter.THREAD_INTERRUPT, ReentrantLock::lockInterruptibly, lock, null, null);
240241
* </pre>
241-
*
242+
*
242243
* @see TruffleSafepoint
243244
* @since 22.1
244245
* @deprecated Use
@@ -318,7 +319,7 @@ public abstract <T, R> R setBlockedFunction(Node location, Interrupter interrupt
318319
* The same as
319320
* {@link #setBlockedFunction(Node, Interrupter, InterruptibleFunction, Object, Runnable, Consumer)}.
320321
* The only difference is that the interruptible functional method does not return anything.
321-
*
322+
*
322323
* @since 23.1
323324
*/
324325
public abstract <T> void setBlocked(Node location, Interrupter interrupter, Interruptible<T> interruptible, T object, Runnable beforeInterrupt,
@@ -433,10 +434,15 @@ public static <T, R> R setBlockedThreadInterruptibleFunction(Node location, Inte
433434
* Important: The result of this method must not be stored or used on a different thread than
434435
* the current thread.
435436
*
437+
* @throws IllegalStateException if the current thread is not entered with a polyglot context.
436438
* @since 21.1
437439
*/
438440
public static TruffleSafepoint getCurrent() {
439-
return HANDSHAKE.getCurrent();
441+
TruffleSafepoint t = HANDSHAKE.getCurrent();
442+
if (t == null) {
443+
throw new IllegalStateException("The TruffleSafepoint mechanism is not initialized on this thread. Did you call getCurrent() while a polyglot context is not entered?");
444+
}
445+
return t;
440446
}
441447

442448
/**

truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultThreadLocalHandshake.java

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@
4242

4343
import java.util.concurrent.atomic.AtomicInteger;
4444

45-
import com.oracle.truffle.api.CompilerDirectives;
4645
import com.oracle.truffle.api.nodes.Node;
4746

4847
final class DefaultThreadLocalHandshake extends ThreadLocalHandshake {
@@ -74,12 +73,7 @@ public void poll(Node enclosingNode) {
7473

7574
@Override
7675
public TruffleSafepointImpl getCurrent() {
77-
TruffleSafepointImpl state = STATE.get();
78-
if (state == null) {
79-
throw CompilerDirectives.shouldNotReachHere("Thread local handshake is not initialized for this thread. " +
80-
"Did you call getCurrent() outside while a polyglot context not entered?");
81-
}
82-
return state;
76+
return STATE.get();
8377
}
8478

8579
@Override

truffle/src/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/ThreadLocalHandshake.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ public void ensureThreadInitialized() {
170170
@TruffleBoundary
171171
protected final void processHandshake(Node location) {
172172
TruffleSafepointImpl s = getCurrent();
173-
if (s.fastPendingSet) {
173+
if (s != null && s.fastPendingSet) {
174174
s.processOrNotifyHandshakes(location, s.takeHandshakes(), null);
175175
}
176176
}
@@ -616,9 +616,9 @@ void verifyUnused() throws AssertionError {
616616
void processOrNotifyHandshakes(Node location, List<HandshakeEntry> toProcessOrNotify, Boolean blockedNotification) {
617617
/*
618618
* blockedNotification == null -> claim and process handshakes
619-
*
619+
*
620620
* blockedNotification == TRUE -> just notify handshakes blocked, don't claim them
621-
*
621+
*
622622
* blockedNotification == FALSE -> just notify handshakes unblocked, don't claim them
623623
*/
624624
if (toProcessOrNotify == null) {

truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/debug/StatisticsListener.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ public synchronized void onCompilationInvalidated(OptimizedCallTarget target, Ob
190190
}
191191

192192
@Override
193-
public void onCompilationStarted(OptimizedCallTarget target, AbstractCompilationTask task) {
193+
public synchronized void onCompilationStarted(OptimizedCallTarget target, AbstractCompilationTask task) {
194194
compilations++;
195195
final CurrentCompilationStatistics times = new CurrentCompilationStatistics(task.tier());
196196
currentCompilationStatistics.set(times);
@@ -291,7 +291,7 @@ public synchronized void onCompilationSuccess(OptimizedCallTarget target, Abstra
291291
}
292292

293293
@Override
294-
public void onCompilationFailed(OptimizedCallTarget target, String reason, boolean bailout, boolean permanentBailout, int tier, Supplier<String> lazyStackTrace) {
294+
public synchronized void onCompilationFailed(OptimizedCallTarget target, String reason, boolean bailout, boolean permanentBailout, int tier, Supplier<String> lazyStackTrace) {
295295
if (bailout) {
296296
if (permanentBailout) {
297297
permanentBailouts++;
@@ -309,7 +309,7 @@ public void onCompilationFailed(OptimizedCallTarget target, String reason, boole
309309
}
310310

311311
@Override
312-
public void onEngineClosed(EngineData runtimeData) {
312+
public synchronized void onEngineClosed(EngineData runtimeData) {
313313
printStatistics(runtimeData);
314314
}
315315

truffle/src/com.oracle.truffle.runtime/src/com/oracle/truffle/runtime/hotspot/HotSpotThreadLocalHandshake.java

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import com.oracle.truffle.api.impl.ThreadLocalHandshake;
4747
import com.oracle.truffle.api.nodes.Node;
4848
import com.oracle.truffle.runtime.ModulesSupport;
49+
4950
import jdk.vm.ci.common.JVMCIError;
5051
import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
5152
import jdk.vm.ci.hotspot.HotSpotVMConfigAccess;
@@ -98,12 +99,7 @@ static void doHandshake(Object node) {
9899
@Override
99100
@TruffleBoundary
100101
public TruffleSafepointImpl getCurrent() {
101-
TruffleSafepointImpl state = STATE.get();
102-
if (state == null) {
103-
throw CompilerDirectives.shouldNotReachHere("Thread local handshake is not initialized for this thread. " +
104-
"Did you call getCurrent() outside while a polyglot context not entered?");
105-
}
106-
return state;
102+
return STATE.get();
107103
}
108104

109105
@Override

0 commit comments

Comments
 (0)