@TruffleBoundary private SafepointAction step(Node currentNode, boolean isDrivingThread) { final DynamicObject thread = context.getThreadManager().getCurrentThread(); // wait other threads to reach their safepoint phaser.arriveAndAwaitAdvance(); if (isDrivingThread) { assumption = Truffle.getRuntime().createAssumption("SafepointManager"); } // wait the assumption to be renewed phaser.arriveAndAwaitAdvance(); // Read these while in the safepoint. SafepointAction deferredAction = deferred ? action : null; try { if (!deferred && thread != null && Layouts.THREAD.getStatus(thread) != Status.ABORTING) { action.run(thread, currentNode); } } finally { // wait other threads to finish their action phaser.arriveAndAwaitAdvance(); } return deferredAction; }
@TruffleBoundary private void assumptionInvalidated(Node currentNode, boolean fromBlockingCall) { final DynamicObject thread = context.getThreadManager().getCurrentThread(); final InterruptMode interruptMode = Layouts.THREAD.getInterruptMode(thread); final boolean interruptible = (interruptMode == InterruptMode.IMMEDIATE) || (fromBlockingCall && interruptMode == InterruptMode.ON_BLOCKING); if (!interruptible) { Thread.currentThread().interrupt(); // keep the interrupt flag return; // interrupt me later } SafepointAction deferredAction = step(currentNode, false); // We're now running again normally and can run deferred actions if (deferredAction != null) { deferredAction.run(thread, currentNode); } }
@TruffleBoundary public void pauseThreadAndExecuteLater( final Thread thread, Node currentNode, final SafepointAction action) { if (Thread.currentThread() == thread) { // fast path if we are already the right thread DynamicObject rubyThread = context.getThreadManager().getCurrentThread(); action.run(rubyThread, currentNode); } else { pauseAllThreadsAndExecute( currentNode, true, new SafepointAction() { @Override public void run(DynamicObject rubyThread, Node currentNode) { if (Thread.currentThread() == thread) { action.run(rubyThread, currentNode); } } }); } }
@TruffleBoundary public void pauseAllThreadsAndExecute( Node currentNode, boolean deferred, SafepointAction action) { if (lock.isHeldByCurrentThread()) { throw new IllegalStateException("Re-entered SafepointManager"); } // Need to lock interruptibly since we are in the registered threads. while (!lock.tryLock()) { poll(currentNode); } try { pauseAllThreadsAndExecute(currentNode, true, action, deferred); } finally { lock.unlock(); } // Run deferred actions after leaving the SafepointManager lock. if (deferred) { action.run(context.getThreadManager().getCurrentThread(), currentNode); } }