Search in sources :

Example 6 with ThreadLocalAction

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);
            }
        }
    });
}
Also used : TruffleSafepoint(com.oracle.truffle.api.TruffleSafepoint) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) ArrayList(java.util.ArrayList) Future(java.util.concurrent.Future) Semaphore(java.util.concurrent.Semaphore) ThreadLocalAction(com.oracle.truffle.api.ThreadLocalAction) TruffleSafepoint(com.oracle.truffle.api.TruffleSafepoint) AbstractPolyglotTest(com.oracle.truffle.api.test.polyglot.AbstractPolyglotTest) Test(org.junit.Test)

Example 7 with ThreadLocalAction

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);
            }
        }
    });
}
Also used : ArrayList(java.util.ArrayList) Semaphore(java.util.concurrent.Semaphore) ThreadLocalAction(com.oracle.truffle.api.ThreadLocalAction) TruffleSafepoint(com.oracle.truffle.api.TruffleSafepoint) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) Future(java.util.concurrent.Future) AbstractPolyglotTest(com.oracle.truffle.api.test.polyglot.AbstractPolyglotTest) Test(org.junit.Test)

Example 8 with ThreadLocalAction

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();
    }
}
Also used : LanguageContext(com.oracle.truffle.api.test.polyglot.ProxyLanguage.LanguageContext) Context(org.graalvm.polyglot.Context) TruffleContext(com.oracle.truffle.api.TruffleContext) Env(com.oracle.truffle.api.TruffleLanguage.Env) ThreadLocalAction(com.oracle.truffle.api.ThreadLocalAction) ProxyLanguage(com.oracle.truffle.api.test.polyglot.ProxyLanguage) Before(org.junit.Before)

Example 9 with ThreadLocalAction

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();
            }
        }
    });
}
Also used : ReentrantLock(java.util.concurrent.locks.ReentrantLock) Condition(java.util.concurrent.locks.Condition) TruffleSafepoint(com.oracle.truffle.api.TruffleSafepoint) ArrayList(java.util.ArrayList) ThreadLocalAction(com.oracle.truffle.api.ThreadLocalAction) TruffleSafepoint(com.oracle.truffle.api.TruffleSafepoint) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Future(java.util.concurrent.Future) AbstractPolyglotTest(com.oracle.truffle.api.test.polyglot.AbstractPolyglotTest) Test(org.junit.Test)

Example 10 with ThreadLocalAction

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();
            }
        }
    });
}
Also used : AtomicReference(java.util.concurrent.atomic.AtomicReference) CountDownLatch(java.util.concurrent.CountDownLatch) ThreadLocalAction(com.oracle.truffle.api.ThreadLocalAction) TruffleSafepoint(com.oracle.truffle.api.TruffleSafepoint) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) AbstractPolyglotTest(com.oracle.truffle.api.test.polyglot.AbstractPolyglotTest) Test(org.junit.Test)

Aggregations

ThreadLocalAction (com.oracle.truffle.api.ThreadLocalAction)19 Test (org.junit.Test)14 AbstractPolyglotTest (com.oracle.truffle.api.test.polyglot.AbstractPolyglotTest)13 TruffleSafepoint (com.oracle.truffle.api.TruffleSafepoint)12 ArrayList (java.util.ArrayList)9 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)9 Future (java.util.concurrent.Future)7 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)6 CountDownLatch (java.util.concurrent.CountDownLatch)5 TruffleContext (com.oracle.truffle.api.TruffleContext)4 List (java.util.List)4 Semaphore (java.util.concurrent.Semaphore)4 AtomicReference (java.util.concurrent.atomic.AtomicReference)4 Env (com.oracle.truffle.api.TruffleLanguage.Env)3 LanguageContext (com.oracle.truffle.api.test.polyglot.ProxyLanguage.LanguageContext)3 ExecutionException (java.util.concurrent.ExecutionException)3 TruffleBoundary (com.oracle.truffle.api.CompilerDirectives.TruffleBoundary)2 ProxyLanguage (com.oracle.truffle.api.test.polyglot.ProxyLanguage)2 HashSet (java.util.HashSet)2 Context (org.graalvm.polyglot.Context)2