Search in sources :

Example 1 with TruffleSafepoint

use of com.oracle.truffle.api.TruffleSafepoint in project graal by oracle.

the class PolyglotContextImpl method finalizeContext.

private void finalizeContext(boolean notifyInstruments, boolean cancelOrExitOperation) {
    // we need to run finalization at least twice in case a finalization run has
    // initialized new contexts
    TruffleSafepoint safepoint = TruffleSafepoint.getCurrent();
    PolyglotThreadLocalActions.TL_HANDSHAKE.setChangeAllowActions(safepoint, true);
    try {
        boolean finalizationPerformed;
        do {
            finalizationPerformed = false;
            // disposal/finalization
            for (int i = contexts.length - 1; i >= 0; i--) {
                PolyglotLanguageContext context = contexts[i];
                if (context.isInitialized()) {
                    try {
                        finalizationPerformed |= context.finalizeContext(cancelOrExitOperation, notifyInstruments);
                    } finally {
                        if (!PolyglotThreadLocalActions.TL_HANDSHAKE.isAllowActions(safepoint)) {
                            safepoint.setAllowActions(true);
                            throw new IllegalStateException("TruffleSafepoint.setAllowActions is still disabled even though finalization completed. Make sure allow actions are reset in a finally block.");
                        }
                    }
                }
            }
        } while (finalizationPerformed);
    } finally {
        PolyglotThreadLocalActions.TL_HANDSHAKE.setChangeAllowActions(safepoint, false);
    }
}
Also used : TruffleSafepoint(com.oracle.truffle.api.TruffleSafepoint) TruffleSafepoint(com.oracle.truffle.api.TruffleSafepoint)

Example 2 with TruffleSafepoint

use of com.oracle.truffle.api.TruffleSafepoint 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 3 with TruffleSafepoint

use of com.oracle.truffle.api.TruffleSafepoint 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 4 with TruffleSafepoint

use of com.oracle.truffle.api.TruffleSafepoint in project graal by oracle.

the class TruffleSafepointTest method testSideEffecting.

@Test
public void testSideEffecting() {
    forEachConfig((threads, events) -> {
        AtomicBoolean stopped = new AtomicBoolean(false);
        try (TestSetup setup = setupSafepointLoop(threads, (s, node) -> {
            TruffleSafepoint config = TruffleSafepoint.getCurrent();
            boolean prev = config.setAllowSideEffects(false);
            try {
                while (true) {
                    TruffleSafepoint.poll(node);
                    if (isStopped(stopped)) {
                        return true;
                    }
                }
            } finally {
                config.setAllowSideEffects(prev);
            }
        })) {
            AtomicInteger eventCounter = new AtomicInteger();
            ActionCollector runnable = new ActionCollector(setup, eventCounter, true, 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);
        }
    });
}
Also used : AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) TruffleSafepoint(com.oracle.truffle.api.TruffleSafepoint) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) TruffleSafepoint(com.oracle.truffle.api.TruffleSafepoint) AbstractPolyglotTest(com.oracle.truffle.api.test.polyglot.AbstractPolyglotTest) Test(org.junit.Test)

Example 5 with TruffleSafepoint

use of com.oracle.truffle.api.TruffleSafepoint in project graal by oracle.

the class BlockingSupport method enterBlockingRegion.

/**
 * Enters a {@link Interruptible} operation on the current thread. This execution will have the
 * following properties:
 * <ul>
 * <li>{@link TruffleSafepoint safepoints} will still be handled.</li>
 * <li>Will throw a {@link GuestInterruptedException} if {@link #guestInterrupt(Thread, Object)}
 * was called on this thread.</li>
 * </ul>
 * Furthermore, no host interruptions of the current thread will result in an
 * {@link InterruptedException}.
 *
 * As such, there are only three ways to retrieve control from a call to this method:
 * <ul>
 * <li>The given {@linkplain Interruptible blockingRegion} naturally completes</li>
 * <li>{@link #guestInterrupt(Thread, Object)} is called for this thread.</li>
 * <li>An {@link ThreadLocalAction action} was submitted to this thread, that throws an
 * exception that is not an {@link InterruptedException}.</li>
 * </ul>
 *
 * @throws GuestInterruptedException if the current thread was guest-interrupted.
 */
@TruffleBoundary
public <U> void enterBlockingRegion(Interruptible<U> blockingRegion, Node location, U object) throws GuestInterruptedException {
    TruffleSafepoint safepoint = TruffleSafepoint.getCurrent();
    safepoint.setBlockedWithException(location, guestInterrupter, blockingRegion, object, null, guestInterrupter::afterInterrupt);
}
Also used : TruffleSafepoint(com.oracle.truffle.api.TruffleSafepoint) TruffleBoundary(com.oracle.truffle.api.CompilerDirectives.TruffleBoundary)

Aggregations

TruffleSafepoint (com.oracle.truffle.api.TruffleSafepoint)11 AbstractPolyglotTest (com.oracle.truffle.api.test.polyglot.AbstractPolyglotTest)5 Test (org.junit.Test)5 TruffleBoundary (com.oracle.truffle.api.CompilerDirectives.TruffleBoundary)4 ThreadLocalAction (com.oracle.truffle.api.ThreadLocalAction)4 ArrayList (java.util.ArrayList)4 AtomicBoolean (java.util.concurrent.atomic.AtomicBoolean)4 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)4 Future (java.util.concurrent.Future)3 TruffleContext (com.oracle.truffle.api.TruffleContext)1 ProxyLanguage (com.oracle.truffle.api.test.polyglot.ProxyLanguage)1 LanguageContext (com.oracle.truffle.api.test.polyglot.ProxyLanguage.LanguageContext)1 UncaughtExceptionHandler (java.lang.Thread.UncaughtExceptionHandler)1 HashSet (java.util.HashSet)1 List (java.util.List)1 CountDownLatch (java.util.concurrent.CountDownLatch)1 ExecutionException (java.util.concurrent.ExecutionException)1 Semaphore (java.util.concurrent.Semaphore)1 Condition (java.util.concurrent.locks.Condition)1 ReentrantLock (java.util.concurrent.locks.ReentrantLock)1