use of com.oracle.truffle.api.TruffleSafepoint in project graal by oracle.
the class BlockingSupport method enterBlockingRegion.
/**
* Same as {@link #enterBlockingRegion(Interruptible, Node, Object)}, but allows providing
* something to execute before and/or after the thread is interrupted and safepoints are
* processed.
*
* @throws GuestInterruptedException if the current thread was guest-interrupted.
*/
@TruffleBoundary
public <U> void enterBlockingRegion(Interruptible<U> blockingRegion, Node location, U object, Runnable beforeSafepoint, Consumer<Throwable> afterSafepoint) throws GuestInterruptedException {
TruffleSafepoint safepoint = TruffleSafepoint.getCurrent();
safepoint.setBlockedWithException(location, guestInterrupter, blockingRegion, object, beforeSafepoint, (ex) -> {
if (afterSafepoint != null) {
afterSafepoint.accept(ex);
}
guestInterrupter.afterInterrupt(ex);
});
}
use of com.oracle.truffle.api.TruffleSafepoint in project graal by oracle.
the class TruffleSafepointTest method testNoSafepointAfterThreadDispose.
@Test
public void testNoSafepointAfterThreadDispose() {
final ThreadLocal<Boolean> tl = new ThreadLocal<>();
ProxyLanguage.setDelegate(new ProxyLanguage() {
@Override
@TruffleBoundary
protected void initializeThread(LanguageContext context, Thread thread) {
tl.set(Boolean.TRUE);
}
@Override
@TruffleBoundary
protected void disposeThread(LanguageContext context, Thread thread) {
tl.set(Boolean.FALSE);
}
@Override
protected boolean isThreadAccessAllowed(Thread thread, boolean singleThreaded) {
return true;
}
});
forEachConfig((threads, events) -> {
CountDownLatch awaitThreadStart = new CountDownLatch(1);
AtomicBoolean threadsStopped = new AtomicBoolean();
try (TestSetup setup = setupSafepointLoop(threads, new NodeCallable() {
@TruffleBoundary
public boolean call(@SuppressWarnings("hiding") TestSetup setup, TestRootNode node) {
try {
List<Throwable> errors = Collections.synchronizedList(new ArrayList<>());
List<Thread> polyglotThreads = new ArrayList<>();
try {
for (int i = 0; i < threads; i++) {
Thread t = node.setup.env.createThread(() -> {
do {
TruffleContext context = node.setup.env.getContext();
TruffleSafepoint safepoint = TruffleSafepoint.getCurrent();
boolean prevSideEffects = safepoint.setAllowSideEffects(false);
try {
context.leaveAndEnter(null, () -> {
// cached thread local
return null;
});
} finally {
safepoint.setAllowSideEffects(prevSideEffects);
}
} while (!threadsStopped.get());
});
t.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
public void uncaughtException(@SuppressWarnings("hiding") Thread t, Throwable e) {
threadsStopped.set(true);
e.printStackTrace();
errors.add(e);
}
});
t.start();
polyglotThreads.add(t);
}
} finally {
awaitThreadStart.countDown();
}
for (Thread thread : polyglotThreads) {
thread.join();
}
for (Throwable t : errors) {
throw new AssertionError("thread threw error ", t);
}
return true;
} catch (InterruptedException e1) {
throw new AssertionError(e1);
}
}
})) {
try {
awaitThreadStart.await();
// important to let leaving and submitting race against each other
threadsStopped.set(true);
List<Future<?>> futures = new ArrayList<>();
for (int i = 0; i < events; i++) {
futures.add(setup.env.submitThreadLocal(null, new ThreadLocalAction(true, false) {
@Override
protected void perform(Access access) {
assertEquals(Boolean.TRUE, tl.get());
}
}));
}
for (Future<?> future : futures) {
try {
future.get();
} catch (ExecutionException e) {
throw new AssertionError(e);
}
}
} catch (InterruptedException e) {
throw new AssertionError(e);
}
setup.stopAndAwait();
}
});
ProxyLanguage.setDelegate(new ProxyLanguage());
}
use of com.oracle.truffle.api.TruffleSafepoint in project graal by oracle.
the class TruffleSafepointTest method testHasPendingSideEffectingActionsBoundary.
@TruffleBoundary
private static void testHasPendingSideEffectingActionsBoundary(AtomicReference<Thread> thread, CountDownLatch waitSideEffectsDisabled, CountDownLatch waitSubmitted, TestRootNode node) throws AssertionError {
TruffleSafepoint safepoint = TruffleSafepoint.getCurrent();
assertFalse(safepoint.hasPendingSideEffectingActions());
boolean prev = safepoint.setAllowSideEffects(false);
try {
thread.set(Thread.currentThread());
waitSideEffectsDisabled.countDown();
try {
waitSubmitted.await();
} catch (InterruptedException e) {
throw new AssertionError(e);
}
assertTrue(safepoint.hasPendingSideEffectingActions());
} finally {
safepoint.setAllowSideEffects(prev);
}
assertFalse("always false when side effects enabled", safepoint.hasPendingSideEffectingActions());
try {
TruffleSafepoint.pollHere(node);
fail();
} catch (RuntimeException e) {
assertEquals("interrupt", e.getMessage());
assertFalse(safepoint.hasPendingSideEffectingActions());
}
}
use of com.oracle.truffle.api.TruffleSafepoint in project graal by oracle.
the class TruffleSafepointTest method testAllowActions.
@Test
public void testAllowActions() {
forEachConfig((threads, events) -> {
AtomicBoolean stopped = new AtomicBoolean(false);
try (TestSetup setup = setupSafepointLoop(threads, (s, node) -> {
TruffleSafepoint config = TruffleSafepoint.getCurrent();
TL_HANDSHAKE.setChangeAllowActions(config, true);
boolean prev = config.setAllowActions(false);
try {
while (true) {
TruffleSafepoint.poll(node);
if (isStopped(stopped)) {
return true;
}
}
} finally {
config.setAllowActions(prev);
TL_HANDSHAKE.setChangeAllowActions(config, false);
}
})) {
AtomicInteger eventCounter = new AtomicInteger();
ActionCollector runnable = new ActionCollector(setup, eventCounter, false, false);
for (int i = 0; i < events; i++) {
setup.env.submitThreadLocal(null, runnable);
}
assertEquals(0, eventCounter.get());
stopped.set(true);
setup.stopAndAwait();
assertActionsAnyOrder(threads, events, runnable);
}
});
}
use of com.oracle.truffle.api.TruffleSafepoint in project graal by oracle.
the class PolyglotThreadLocalActions method notifyThreadActivation.
Set<ThreadLocalAction> notifyThreadActivation(PolyglotThreadInfo info, boolean active) {
assert !active || info.getEnteredCount() == 1 : "must be currently entered successfully";
assert Thread.holdsLock(context);
if (activeEvents.isEmpty()) {
// fast common path
return Collections.emptySet();
}
Set<ThreadLocalAction> updatedActions = new HashSet<>();
// we cannot process the events while the context lock is held
// so we need to collect them first.
TruffleSafepoint s = TruffleSafepoint.getCurrent();
/*
* The set can be modified during the subsequent iteration.
*/
ArrayList<AbstractTLHandshake> activeEventsList = new ArrayList<>(activeEvents.keySet());
for (AbstractTLHandshake handshake : activeEventsList) {
if (!handshake.isEnabledForThread(Thread.currentThread())) {
continue;
}
Future<?> f = handshake.future;
if (f instanceof RecurringFuture) {
f = ((RecurringFuture) f).getCurrentFuture();
assert f != null : "current future must never be null";
}
if (active) {
if (traceActions) {
log("activate", handshake, "");
}
if (f == COMPLETED_FUTURE) {
assert handshake.future instanceof RecurringFuture;
handshake.resubmitRecurring();
} else {
if (TL_HANDSHAKE.activateThread(s, f)) {
updatedActions.add(handshake.action);
}
}
} else {
if (traceActions) {
log("deactivate", handshake, "");
}
if (f == COMPLETED_FUTURE) {
assert handshake.future instanceof RecurringFuture;
// nothing to do, wait for reactivation
} else {
if (TL_HANDSHAKE.deactivateThread(s, f)) {
updatedActions.add(handshake.action);
}
}
}
}
return updatedActions;
}
Aggregations