Search in sources :

Example 1 with ThreadLocalAction

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

the class PolyglotContextImpl method enterThreadChanged.

/**
 * Use to enter context if it's guaranteed to be called rarely and configuration flexibility is
 * needed. Otherwise use {@link PolyglotEngineImpl#enter(PolyglotContextImpl)}.
 */
@TruffleBoundary
Object[] enterThreadChanged(boolean notifyEnter, boolean enterReverted, boolean pollSafepoint, boolean deactivateSafepoints) {
    PolyglotThreadInfo enteredThread = null;
    Object[] prev = null;
    try {
        Thread current = Thread.currentThread();
        boolean needsInitialization = false;
        synchronized (this) {
            PolyglotThreadInfo threadInfo = getCurrentThreadInfo();
            if (enterReverted && threadInfo.getEnteredCount() == 0) {
                threadLocalActions.notifyThreadActivation(threadInfo, false);
                if ((state.isCancelling() || state.isExiting() || state == State.CLOSED_CANCELLED || state == State.CLOSED_EXITED) && !threadInfo.isActive()) {
                    notifyThreadClosed(threadInfo);
                }
                if (state.isInterrupting() && !threadInfo.isActive()) {
                    Thread.interrupted();
                    notifyAll();
                }
            }
            if (deactivateSafepoints && threadInfo != PolyglotThreadInfo.NULL) {
                threadLocalActions.notifyThreadActivation(threadInfo, false);
            }
            checkClosed();
            assert threadInfo != null;
            threadInfo = threads.get(current);
            if (threadInfo == null) {
                threadInfo = createThreadInfo(current);
                needsInitialization = true;
            }
            if (singleThreaded) {
                /*
                     * If this is the only thread, then setting the cached thread info to NULL is no
                     * performance problem. If there is other thread that is just about to enter, we
                     * are making sure that it initializes multi-threading if this thread doesn't do
                     * it.
                     */
                setCachedThreadInfo(PolyglotThreadInfo.NULL);
            }
            boolean transitionToMultiThreading = isSingleThreaded() && hasActiveOtherThread(true);
            if (transitionToMultiThreading) {
                // recheck all thread accesses
                checkAllThreadAccesses(Thread.currentThread(), false);
            }
            if (transitionToMultiThreading) {
                /*
                     * We need to do this early (before initializeMultiThreading) as entering or
                     * local initialization depends on single thread per context.
                     */
                engine.singleThreadPerContext.invalidate();
                singleThreaded = false;
            }
            if (needsInitialization) {
                threads.put(current, threadInfo);
            }
            if (needsInitialization) {
                /*
                     * Do not enter the thread before initializing thread locals. Creation of thread
                     * locals might fail.
                     */
                initializeThreadLocals(threadInfo);
            }
            prev = threadInfo.enterInternal();
            if (notifyEnter) {
                try {
                    threadInfo.notifyEnter(engine, this);
                } catch (Throwable t) {
                    threadInfo.leaveInternal(prev);
                    throw t;
                }
            }
            enteredThread = threadInfo;
            if (needsInitialization) {
                this.threadLocalActions.notifyEnterCreatedThread();
            }
            // new thread became active so we need to check potential active thread local
            // actions and process them.
            Set<ThreadLocalAction> activatedActions = null;
            if (enteredThread.getEnteredCount() == 1 && !deactivateSafepoints) {
                activatedActions = threadLocalActions.notifyThreadActivation(threadInfo, true);
            }
            if (transitionToMultiThreading) {
                // we need to verify that all languages give access
                // to all threads in multi-threaded mode.
                transitionToMultiThreaded();
            }
            if (needsInitialization) {
                initializeNewThread(current);
            }
            if (enteredThread.getEnteredCount() == 1 && !pauseThreadLocalActions.isEmpty()) {
                for (Iterator<PauseThreadLocalAction> threadLocalActionIterator = pauseThreadLocalActions.iterator(); threadLocalActionIterator.hasNext(); ) {
                    PauseThreadLocalAction threadLocalAction = threadLocalActionIterator.next();
                    if (!threadLocalAction.isPause()) {
                        threadLocalActionIterator.remove();
                    } else {
                        if (activatedActions == null || !activatedActions.contains(threadLocalAction)) {
                            threadLocalActions.submit(new Thread[] { Thread.currentThread() }, PolyglotEngineImpl.ENGINE_ID, threadLocalAction, new HandshakeConfig(true, true, false, false));
                        }
                    }
                }
            }
            // never cache last thread on close or when closingThread
            setCachedThreadInfo(threadInfo);
        }
        if (needsInitialization) {
            EngineAccessor.INSTRUMENT.notifyThreadStarted(engine, creatorTruffleContext, current);
        }
        return prev;
    } finally {
        /*
             * We need to always poll the safepoint here in case we already submitted a thread local
             * action for this thread. Not polling here would make dependencies of that event wait
             * forever.
             */
        if (pollSafepoint) {
            try {
                TruffleSafepoint.pollHere(this.uncachedLocation);
            } catch (Throwable t) {
                /*
                     * Just in case a safepoint makes the enter fail we need to leave the context
                     * again.
                     */
                if (enteredThread != null) {
                    this.leaveThreadChanged(prev, notifyEnter, true);
                }
                throw t;
            }
        }
    }
}
Also used : HandshakeConfig(com.oracle.truffle.polyglot.PolyglotThreadLocalActions.HandshakeConfig) TruffleObject(com.oracle.truffle.api.interop.TruffleObject) ThreadLocalAction(com.oracle.truffle.api.ThreadLocalAction) TruffleBoundary(com.oracle.truffle.api.CompilerDirectives.TruffleBoundary)

Example 2 with ThreadLocalAction

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

the class OptimizedOSRLoopNodeTest method testSafepointLocationInLoop.

/*
     * Test that thread local actions never expose the OSR root node.
     */
@Theory
public void testSafepointLocationInLoop(OSRLoopFactory factory) {
    TestRootNode rootNode = new TestRootNode(osrThreshold, factory, new TestRepeatingNode());
    // avoid thread local action being processed right away
    context.leave();
    AtomicBoolean locationAssertEnabled = new AtomicBoolean(false);
    AtomicInteger safepointCounter = new AtomicInteger(0);
    Future<?> f = languageEnv.submitThreadLocal(null, new ThreadLocalAction(false, false, true) {

        @Override
        protected void perform(Access access) {
            // recurring
            if (locationAssertEnabled.get()) {
                // we need to make sure we never observe the OSR root node here.
                // we expect either the loop node or the root node of the loop node as location.
                Assert.assertTrue(access.getLocation().toString(), access.getLocation() == rootNode || access.getLocation() == rootNode.loopNode);
                Assert.assertSame(Truffle.getRuntime().getCurrentFrame().getCallTarget(), rootNode.getCallTarget());
                safepointCounter.incrementAndGet();
            }
        }
    });
    context.enter();
    // enter or close might trigger safepoints, but we have no guarantees on the location there
    locationAssertEnabled.set(true);
    try {
        assertNotCompiled(rootNode.getOSRTarget());
        // triggers
        rootNode.getCallTarget().call(osrThreshold + 1);
        assertCompiled(rootNode.getOSRTarget());
        assertTrue(safepointCounter.get() > 0);
    } finally {
        f.cancel(true);
    }
}
Also used : AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) ThreadLocalAction(com.oracle.truffle.api.ThreadLocalAction) Theory(org.junit.experimental.theories.Theory)

Example 3 with ThreadLocalAction

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

the class PolyglotStackFramesRetriever method getStackFrames.

@SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter")
static FrameInstance[][] getStackFrames(PolyglotContextImpl context) {
    Map<Thread, List<FrameInstance>> frameInstancesByThread = new ConcurrentHashMap<>();
    Thread[] threads;
    Future<Void> future;
    synchronized (context) {
        threads = context.getSeenThreads().keySet().toArray(new Thread[0]);
        if (!context.state.isClosed()) {
            future = context.threadLocalActions.submit(null, PolyglotEngineImpl.ENGINE_ID, new ThreadLocalAction(false, false) {

                @Override
                protected void perform(Access access) {
                    List<FrameInstance> frameInstances = new ArrayList<>();
                    Truffle.getRuntime().iterateFrames(new FrameInstanceVisitor<>() {

                        @Override
                        public Object visitFrame(FrameInstance frameInstance) {
                            return frameInstances.add(frameInstance);
                        }
                    });
                    frameInstancesByThread.put(access.getThread(), frameInstances);
                }
            }, false);
        } else {
            future = CompletableFuture.completedFuture(null);
        }
    }
    TruffleSafepoint.setBlockedThreadInterruptible(context.uncachedLocation, new TruffleSafepoint.Interruptible<Future<Void>>() {

        @Override
        public void apply(Future<Void> arg) throws InterruptedException {
            try {
                arg.get();
            } catch (ExecutionException e) {
                throw CompilerDirectives.shouldNotReachHere(e);
            }
        }
    }, future);
    FrameInstance[][] toRet = new FrameInstance[threads.length][];
    for (int i = 0; i < threads.length; i++) {
        Thread thread = threads[i];
        List<FrameInstance> frameInstances = frameInstancesByThread.get(thread);
        if (frameInstances != null) {
            toRet[i] = frameInstances.toArray(new FrameInstance[0]);
        } else {
            toRet[i] = new FrameInstance[0];
        }
    }
    return toRet;
}
Also used : TruffleSafepoint(com.oracle.truffle.api.TruffleSafepoint) ArrayList(java.util.ArrayList) ThreadLocalAction(com.oracle.truffle.api.ThreadLocalAction) TruffleSafepoint(com.oracle.truffle.api.TruffleSafepoint) FrameInstance(com.oracle.truffle.api.frame.FrameInstance) CompletableFuture(java.util.concurrent.CompletableFuture) Future(java.util.concurrent.Future) ArrayList(java.util.ArrayList) List(java.util.List) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) ExecutionException(java.util.concurrent.ExecutionException)

Example 4 with ThreadLocalAction

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

the class TruffleSafepointTest method testEventCancellation.

/*
     * Test that future cancel actually cancels the event.
     */
@Test
public void testEventCancellation() {
    forEachConfig((threads, events) -> {
        try (TestSetup setup = setupSafepointLoop(threads, (s, node) -> {
            sleepNanosBoundary(50000);
            TruffleSafepoint.poll(node);
            return false;
        })) {
            List<Future<Void>> futures = new ArrayList<>();
            for (int i = 0; i < events; i++) {
                Future<Void> f = (setup.env.submitThreadLocal(null, new ThreadLocalAction(false, false) {

                    @Override
                    protected void perform(Access innerAccess) {
                    }
                }));
                if (f.cancel(false)) {
                    assertTrue(f.isDone());
                    assertTrue(f.isCancelled());
                }
                futures.add(f);
            }
            for (Future<Void> future : futures) {
                waitOrFail(future);
            }
        }
    });
}
Also used : ArrayList(java.util.ArrayList) Future(java.util.concurrent.Future) 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 5 with ThreadLocalAction

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

the class TruffleSafepointTest method testEnterSlowPathFallback.

@Test
public void testEnterSlowPathFallback() throws ExecutionException, InterruptedException {
    ExecutorService executorService = Executors.newFixedThreadPool(1);
    try {
        for (int itNo = 0; itNo < 1000; itNo++) {
            CountDownLatch enterLeaveLoopLatch = new CountDownLatch(1);
            AtomicReference<Env> envAtomicReference = new AtomicReference<>();
            AtomicReference<Context> contextAtomicReference = new AtomicReference<>();
            Future<?> testFuture = executorService.submit(() -> {
                /*
                     * The context is closed in main thread. Closing it here in try-with-resources
                     * block would only make the test more complex.
                     */
                Context c = createTestContext();
                contextAtomicReference.set(c);
                c.initialize(ProxyLanguage.ID);
                c.enter();
                try {
                    envAtomicReference.set(LanguageContext.get(null).getEnv());
                } finally {
                    c.leave();
                }
                enterLeaveLoopLatch.countDown();
                TruffleContext truffleContext = envAtomicReference.get().getContext();
                try {
                    for (int i = 0; i < 100000; i++) {
                        Object prev = truffleContext.enter(INVALID_NODE);
                        truffleContext.leave(INVALID_NODE, prev);
                    }
                } catch (Throwable t) {
                    if (!"Context execution was cancelled.".equals(t.getMessage())) {
                        throw t;
                    }
                }
            });
            enterLeaveLoopLatch.await();
            Context c = contextAtomicReference.get();
            Env env = envAtomicReference.get();
            TruffleContext truffleContext = env.getContext();
            /*
                 * The goal of this test is to check whether the slowpath fallback in thread enter
                 * guarantees that the thread local action is either polled when the context is
                 * entered, or the thread is deactivated.
                 */
            AtomicBoolean threadLocalActionPerformedWhenContextWasInactive = new AtomicBoolean();
            Future<?> future = submitThreadLocalInternal(env, null, new ThreadLocalAction(false, false) {

                @Override
                protected void perform(Access access) {
                    if (!truffleContext.isActive()) {
                        threadLocalActionPerformedWhenContextWasInactive.set(true);
                    }
                }
            }, false);
            c.close(true);
            future.get();
            testFuture.get();
            assertFalse("Action was performed when inactive in iteration " + itNo, threadLocalActionPerformedWhenContextWasInactive.get());
        }
    } finally {
        executorService.shutdownNow();
        executorService.awaitTermination(100, TimeUnit.SECONDS);
    }
}
Also used : LanguageContext(com.oracle.truffle.api.test.polyglot.ProxyLanguage.LanguageContext) Context(org.graalvm.polyglot.Context) TruffleContext(com.oracle.truffle.api.TruffleContext) TruffleContext(com.oracle.truffle.api.TruffleContext) AtomicReference(java.util.concurrent.atomic.AtomicReference) CountDownLatch(java.util.concurrent.CountDownLatch) Env(com.oracle.truffle.api.TruffleLanguage.Env) ThreadLocalAction(com.oracle.truffle.api.ThreadLocalAction) TruffleSafepoint(com.oracle.truffle.api.TruffleSafepoint) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) ExecutorService(java.util.concurrent.ExecutorService) 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