use of com.oracle.truffle.api.ThreadLocalAction in project graal by oracle.
the class TruffleSafepointTest method testBlockedAndSafepoints.
/*
* This test case is inspired by the ruby use case of disabling side-effects and block to wake
* up to allow side-effecting effects a forced location.
*/
@Test
public void testBlockedAndSafepoints() {
forEachConfig((threads, events) -> {
Semaphore semaphore = new Semaphore(threads);
try (TestSetup setup = setupSafepointLoop(threads, (s, node) -> {
TruffleSafepoint safepoint = TruffleSafepoint.getCurrent();
lockCooperativelySafepoint(semaphore, node, safepoint);
return false;
})) {
try {
AtomicInteger eventCounter = new AtomicInteger();
List<Future<?>> threadLocals = new ArrayList<>();
for (int i = 0; i < events; i++) {
threadLocals.add(setup.env.submitThreadLocal(null, new ThreadLocalAction(true, false) {
@Override
protected void perform(Access access) {
assertNotSame(INVALID_NODE, access.getLocation());
assertSame(setup.target.getRootNode(), access.getLocation());
eventCounter.incrementAndGet();
}
}));
// this encourages race conditions between setting blocked and unlocking
if (i == Math.floorDiv(events, 2)) {
for (int j = 0; j < threads; j++) {
acquire(semaphore);
}
}
}
// wait for all events to complete so we can reliably assert the events
for (Future<?> f : threadLocals) {
waitOrFail(f);
}
assertEquals(events * threads, eventCounter.get());
} finally {
// let the threads complete in an orderly fashing
// events can happen in any order
semaphore.release(threads);
}
}
});
}
use of com.oracle.truffle.api.ThreadLocalAction in project graal by oracle.
the class TruffleSafepointTest method testContextCancellation.
/*
* All events are cancelled or performed as soon as the context is closed, otherwise the context
* close throws an error.
*/
@Test
public void testContextCancellation() {
forEachConfig((threads, events) -> {
List<Throwable> exceptions = Collections.synchronizedList(new ArrayList<>());
try (TestSetup setup = setupSafepointLoop(threads, (s, node) -> {
sleepNanosBoundary(50000);
TruffleSafepoint.poll(node);
return false;
}, new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) {
exceptions.add(throwable);
}
})) {
AtomicBoolean closed = new AtomicBoolean();
List<Future<?>> threadLocals = new ArrayList<>();
Semaphore awaitClosing = new Semaphore(0);
Future<?> closing = service.submit(() -> {
awaitClosing.release();
setup.context.close(true);
closed.set(true);
});
for (int i = 0; i < events; i++) {
threadLocals.add(setup.env.submitThreadLocal(null, new ThreadLocalAction(false, false) {
@Override
protected void perform(Access innerAccess) {
if (closed.get()) {
fail("no event should ever be called if context is closed");
}
}
}));
}
acquire(awaitClosing);
// we need to allow threads to complete before we cancel
// this is necessary because we still use instrumentation for cancel and we are
// not
// using instrumented nodes here.
setup.stopped.set(true);
waitOrFail(closing);
}
for (Throwable exception : exceptions) {
if (!(exception instanceof ThreadDeath)) {
throw new AssertionError(exception);
}
}
});
}
use of com.oracle.truffle.api.ThreadLocalAction in project graal by oracle.
the class TruffleSafepointTest method before.
@Before
public void before() throws ExecutionException, InterruptedException {
ProxyLanguage.setDelegate(new ProxyLanguage() {
@Override
protected boolean isThreadAccessAllowed(Thread thread, boolean singleThreaded) {
return true;
}
});
boolean handshakesSupported = true;
Future<Void> future = null;
try (Context c = createTestContext()) {
c.enter();
try {
c.initialize(ProxyLanguage.ID);
Env env = LanguageContext.get(null).getEnv();
try {
future = env.submitThreadLocal(null, new ThreadLocalAction(false, false) {
@Override
protected void perform(Access access) {
}
});
} catch (UnsupportedOperationException e) {
if ("Thread local handshakes are not supported on this platform. A possible reason may be that the underlying JVMCI version is too old.".equals(e.getMessage())) {
handshakesSupported = false;
} else {
throw e;
}
}
} finally {
c.leave();
}
}
if (future != null) {
future.get();
}
Assume.assumeTrue(handshakesSupported);
if (VERBOSE) {
System.out.println();
System.out.print(name.getMethodName() + ":");
testStarted = System.currentTimeMillis();
}
}
use of com.oracle.truffle.api.ThreadLocalAction in project graal by oracle.
the class TruffleSafepointTest method testConditionAndSafepoints.
@Test
public void testConditionAndSafepoints() {
forEachConfig((threads, events) -> {
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
AtomicBoolean done = new AtomicBoolean(false);
AtomicInteger inAwait = new AtomicInteger(0);
try (TestSetup setup = setupSafepointLoop(threads, (s, node) -> {
TruffleSafepoint safepoint = TruffleSafepoint.getCurrent();
// No lockInterruptibly()/setBlocked() here, `lock` is never held during a poll()
// It can also be required by language semantics if only the await() should be
// interruptible and not the lock().
lockBoundary(lock);
try {
while (!done.get()) {
safepoint.setBlockedWithException(node, Interrupter.THREAD_INTERRUPT, (c) -> {
// When await() is interrupted, it still needs to
// reacquire the lock before the InterruptedException
// can propagate. So we must unlock once we're out to
// let other threads reach the safepoint too.
inAwait.incrementAndGet();
try {
c.await();
} finally {
inAwait.decrementAndGet();
}
}, condition, lock::unlock, (t) -> lock.lock());
}
} finally {
unlockBoundary(lock);
}
// only run once
return true;
})) {
AtomicInteger eventCounter = new AtomicInteger();
// Wait all threads are inside await()
while (inAwait.get() < threads || lock.isLocked()) {
Thread.yield();
}
List<Future<?>> threadLocals = new ArrayList<>();
for (int i = 0; i < events; i++) {
threadLocals.add(setup.env.submitThreadLocal(null, new ThreadLocalAction(false, true) {
@Override
protected void perform(Access access) {
Assert.assertFalse(lock.isHeldByCurrentThread());
eventCounter.incrementAndGet();
}
}));
}
// wait for all events to complete so we can reliably assert the events
for (Future<?> f : threadLocals) {
waitOrFail(f);
}
assertEquals(events * threads, eventCounter.get());
// Wait all threads are in condition.await(), otherwise signalAll() doesn't work
while (inAwait.get() < threads || lock.isLocked()) {
Thread.yield();
}
lock.lock();
try {
done.set(true);
condition.signalAll();
} finally {
lock.unlock();
}
}
});
}
use of com.oracle.truffle.api.ThreadLocalAction in project graal by oracle.
the class TruffleSafepointTest method testException.
@Test
public void testException() {
forEachConfig((threads, events) -> {
AtomicReference<CountDownLatch> latchRef = new AtomicReference<>(null);
List<Throwable> exceptions = Collections.synchronizedList(new ArrayList<>());
try (TestSetup setup = setupSafepointLoop(threads, (s, node) -> {
sleepNanosBoundary(50000);
TruffleSafepoint.poll(node);
return false;
}, (e) -> {
exceptions.add(e);
latchRef.get().countDown();
})) {
for (int i = 0; i < events; i++) {
CountDownLatch latch = new CountDownLatch(threads);
latchRef.set(latch);
String testId = "test " + i + " of " + events;
AtomicInteger counter = new AtomicInteger();
Future<?> await = setup.env.submitThreadLocal(null, new ThreadLocalAction(true, false) {
@Override
protected void perform(Access access) {
counter.incrementAndGet();
throw new RuntimeException(testId);
}
});
// wait until all tasks on all threads are done
waitOrFail(await);
// make sure we thrown the exception for all events
assertEquals(threads, counter.get());
try {
// wait until all exceptions are reported
if (!latch.await(TIMEOUT_SECONDS, TimeUnit.SECONDS)) {
throw failTimeout(null);
}
} catch (InterruptedException e) {
fail();
}
assertEquals(threads, exceptions.size());
for (Throwable t : exceptions) {
assertTrue(t instanceof RuntimeException);
assertEquals(testId, t.getMessage());
}
exceptions.clear();
}
}
});
}
Aggregations