Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 89c134869eb2
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: c83de9b9006d
Choose a head ref
  • 5 commits
  • 16 files changed
  • 1 contributor

Commits on Jul 23, 2015

  1. Copy the full SHA
    0590488 View commit details
  2. [Truffle] No need to pass the Ruby thread in SafepointManager.

    * The currentThread ThreadLocal will tell us anyway.
    eregon committed Jul 23, 2015
    Copy the full SHA
    be414cf View commit details
  3. Copy the full SHA
    a766ce8 View commit details
  4. Copy the full SHA
    eb332f2 View commit details
  5. [Truffle] Full Kernel#inspect.

    * Just use #to_s if you need to print an object before bootstrap/kernel.rb is loaded.
    eregon committed Jul 23, 2015
    Copy the full SHA
    c83de9b View commit details
2 changes: 0 additions & 2 deletions spec/truffle/tags/core/kernel/inspect_tags.txt

This file was deleted.

Original file line number Diff line number Diff line change
@@ -96,16 +96,15 @@ public static void run(RubyBasicObject fiber, final Runnable task) {
public static void start(RubyBasicObject fiber) {
assert RubyGuards.isRubyFiber(fiber);
getFields(fiber).thread = Thread.currentThread();
fiber.getContext().getThreadManager().initializeCurrentThread(getFields(fiber).rubyThread);
ThreadNodes.getFiberManager(getFields(fiber).rubyThread).registerFiber(fiber);
fiber.getContext().getSafepointManager().enterThread();
fiber.getContext().getThreadManager().enterGlobalLock(getFields(fiber).rubyThread);
}

// Only used by the main thread which cannot easily wrap everything inside a try/finally.
public static void cleanup(RubyBasicObject fiber) {
assert RubyGuards.isRubyFiber(fiber);
getFields(fiber).alive = false;
fiber.getContext().getThreadManager().leaveGlobalLock();
fiber.getContext().getSafepointManager().leaveThread();
ThreadNodes.getFiberManager(getFields(fiber).rubyThread).unregisterFiber(fiber);
getFields(fiber).thread = null;
@@ -124,7 +123,7 @@ private static void sendMessageTo(RubyBasicObject fiber, FiberMessage message) {
private static Object[] waitForResume(final RubyBasicObject fiber) {
assert RubyGuards.isRubyFiber(fiber);

final FiberMessage message = fiber.getContext().getThreadManager().runUntilResult(new ThreadManager.BlockingActionWithoutGlobalLock<FiberMessage>() {
final FiberMessage message = fiber.getContext().getThreadManager().runUntilResult(new ThreadManager.BlockingAction<FiberMessage>() {
@Override
public FiberMessage block() throws InterruptedException {
return getFields(fiber).messageQueue.take();
Original file line number Diff line number Diff line change
@@ -63,7 +63,7 @@
import org.jruby.truffle.runtime.core.RubyClass;
import org.jruby.truffle.runtime.methods.InternalMethod;
import org.jruby.truffle.runtime.subsystems.FeatureManager;
import org.jruby.truffle.runtime.subsystems.ThreadManager.BlockingActionWithoutGlobalLock;
import org.jruby.truffle.runtime.subsystems.ThreadManager.BlockingAction;
import org.jruby.truffle.translator.NodeWrapper;
import org.jruby.truffle.translator.TranslatorDriver;
import org.jruby.util.ByteList;
@@ -685,7 +685,7 @@ private static void exec(RubyContext context, RubyBasicObject envAsHash, String[
throw new RuntimeException(e);
}

int exitCode = context.getThreadManager().runUntilResult(new BlockingActionWithoutGlobalLock<Integer>() {
int exitCode = context.getThreadManager().runUntilResult(new BlockingAction<Integer>() {
@Override
public Integer block() throws InterruptedException {
return process.waitFor();
@@ -826,7 +826,7 @@ public RubyBasicObject gets(VirtualFrame frame) {

final BufferedReader reader = new BufferedReader(new InputStreamReader(in, encoding.getCharset()));

final String line = getContext().getThreadManager().runUntilResult(new BlockingActionWithoutGlobalLock<String>() {
final String line = getContext().getThreadManager().runUntilResult(new BlockingAction<String>() {
@Override
public String block() throws InterruptedException {
return gets(reader);
@@ -1828,7 +1828,7 @@ public static long sleepFor(RubyContext context, final long durationInMillis) {

final long start = System.currentTimeMillis();

long slept = context.getThreadManager().runUntilResult(new BlockingActionWithoutGlobalLock<Long>() {
long slept = context.getThreadManager().runUntilResult(new BlockingAction<Long>() {
@Override
public Long block() throws InterruptedException {
long now = System.currentTimeMillis();
@@ -2077,7 +2077,7 @@ public String toHexString(RubyBasicObject value) {

}

@CoreMethod(names = { "to_s", "inspect" })
@CoreMethod(names = "to_s")
public abstract static class ToSNode extends CoreMethodArrayArgumentsNode {

@Child private ClassNode classNode;
Original file line number Diff line number Diff line change
@@ -22,7 +22,7 @@
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.truffle.runtime.core.RubyBasicObject;
import org.jruby.truffle.runtime.object.BasicObjectType;
import org.jruby.truffle.runtime.subsystems.ThreadManager.BlockingActionWithoutGlobalLock;
import org.jruby.truffle.runtime.subsystems.ThreadManager.BlockingAction;

import java.util.EnumSet;
import java.util.concurrent.locks.ReentrantLock;
@@ -86,7 +86,7 @@ protected static void lock(final ReentrantLock lock, final RubyBasicObject threa
throw new RaiseException(context.getCoreLibrary().threadError("deadlock; recursive locking", currentNode));
}

context.getThreadManager().runUntilResult(new BlockingActionWithoutGlobalLock<Boolean>() {
context.getThreadManager().runUntilResult(new BlockingAction<Boolean>() {
@Override
public Boolean block() throws InterruptedException {
lock.lockInterruptibly();
Original file line number Diff line number Diff line change
@@ -25,7 +25,7 @@
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.truffle.runtime.core.RubyBasicObject;
import org.jruby.truffle.runtime.object.BasicObjectType;
import org.jruby.truffle.runtime.subsystems.ThreadManager.BlockingActionWithoutGlobalLock;
import org.jruby.truffle.runtime.subsystems.ThreadManager.BlockingAction;
import org.jruby.util.unsafe.UnsafeHolder;

import java.util.EnumSet;
@@ -77,7 +77,7 @@ public PushNode(RubyContext context, SourceSection sourceSection) {
public RubyBasicObject push(RubyBasicObject self, final Object value) {
final BlockingQueue<Object> queue = getQueue(self);

getContext().getThreadManager().runUntilResult(new BlockingActionWithoutGlobalLock<Boolean>() {
getContext().getThreadManager().runUntilResult(new BlockingAction<Boolean>() {
@Override
public Boolean block() throws InterruptedException {
queue.put(value);
@@ -110,7 +110,7 @@ public RubyNode coerceToBoolean(RubyNode nonBlocking) {
public Object popBlocking(RubyBasicObject self, boolean nonBlocking) {
final BlockingQueue<Object> queue = getQueue(self);

return getContext().getThreadManager().runUntilResult(new BlockingActionWithoutGlobalLock<Object>() {
return getContext().getThreadManager().runUntilResult(new BlockingAction<Object>() {
@Override
public Object block() throws InterruptedException {
return queue.take();
@@ -213,7 +213,7 @@ public int num_waiting(RubyBasicObject self) {
final ReentrantLock lock = (ReentrantLock) UnsafeHolder.U.getObject(linkedBlockingQueue, LOCK_FIELD_OFFSET);
final Condition notEmptyCondition = (Condition) UnsafeHolder.U.getObject(linkedBlockingQueue, NOT_EMPTY_CONDITION_FIELD_OFFSET);

getContext().getThreadManager().runUntilResult(new BlockingActionWithoutGlobalLock<Boolean>() {
getContext().getThreadManager().runUntilResult(new BlockingAction<Boolean>() {
@Override
public Boolean block() throws InterruptedException {
lock.lockInterruptibly();
Original file line number Diff line number Diff line change
@@ -28,7 +28,7 @@
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.truffle.runtime.core.RubyBasicObject;
import org.jruby.truffle.runtime.object.BasicObjectType;
import org.jruby.truffle.runtime.subsystems.ThreadManager.BlockingActionWithoutGlobalLock;
import org.jruby.truffle.runtime.subsystems.ThreadManager.BlockingAction;
import org.jruby.util.unsafe.UnsafeHolder;

import java.util.concurrent.ArrayBlockingQueue;
@@ -167,7 +167,7 @@ public RubyNode coerceToBoolean(RubyNode nonBlocking) {
public RubyBasicObject pushBlocking(RubyBasicObject self, final Object value, boolean nonBlocking) {
final BlockingQueue<Object> queue = getQueue(self);

getContext().getThreadManager().runUntilResult(new BlockingActionWithoutGlobalLock<Boolean>() {
getContext().getThreadManager().runUntilResult(new BlockingAction<Boolean>() {
@Override
public Boolean block() throws InterruptedException {
queue.put(value);
@@ -213,7 +213,7 @@ public RubyNode coerceToBoolean(RubyNode nonBlocking) {
public Object popBlocking(RubyBasicObject self, boolean nonBlocking) {
final BlockingQueue<Object> queue = getQueue(self);

return getContext().getThreadManager().runUntilResult(new BlockingActionWithoutGlobalLock<Object>() {
return getContext().getThreadManager().runUntilResult(new BlockingAction<Object>() {
@Override
public Object block() throws InterruptedException {
return queue.take();
@@ -303,7 +303,7 @@ public int num_waiting(RubyBasicObject self) {
final Condition notEmptyCondition = (Condition) UnsafeHolder.U.getObject(arrayBlockingQueue, NOT_EMPTY_CONDITION_FIELD_OFFSET);
final Condition notFullCondition = (Condition) UnsafeHolder.U.getObject(arrayBlockingQueue, NOT_FULL_CONDITION_FIELD_OFFSET);

getContext().getThreadManager().runUntilResult(new BlockingActionWithoutGlobalLock<Boolean>() {
getContext().getThreadManager().runUntilResult(new BlockingAction<Boolean>() {
@Override
public Boolean block() throws InterruptedException {
lock.lockInterruptibly();
Original file line number Diff line number Diff line change
@@ -125,7 +125,7 @@ public static Thread getCurrentFiberJavaThread(RubyBasicObject thread) {

public static void join(final RubyBasicObject thread) {
assert RubyGuards.isRubyThread(thread);
getFields(((RubyThread) thread)).manager.runUntilResult(new ThreadManager.BlockingActionWithoutGlobalLock<Boolean>() {
getFields(((RubyThread) thread)).manager.runUntilResult(new ThreadManager.BlockingAction<Boolean>() {
@Override
public Boolean block() throws InterruptedException {
getFields(((RubyThread) thread)).finished.await();
@@ -141,7 +141,7 @@ public Boolean block() throws InterruptedException {
public static boolean join(final RubyBasicObject thread, final int timeoutInMillis) {
assert RubyGuards.isRubyThread(thread);
final long start = System.currentTimeMillis();
final boolean joined = getFields(((RubyThread) thread)).manager.runUntilResult(new ThreadManager.BlockingActionWithoutGlobalLock<Boolean>() {
final boolean joined = getFields(((RubyThread) thread)).manager.runUntilResult(new ThreadManager.BlockingAction<Boolean>() {
@Override
public Boolean block() throws InterruptedException {
long now = System.currentTimeMillis();
Original file line number Diff line number Diff line change
@@ -13,7 +13,6 @@
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.core.RubyBasicObject;

public class ThreadPassNode extends RubyNode {

@@ -23,13 +22,7 @@ public ThreadPassNode(RubyContext context, SourceSection sourceSection) {

@Override
public void executeVoid(VirtualFrame frame) {
final RubyBasicObject runningThread = getContext().getThreadManager().leaveGlobalLock();

try {
Thread.yield();
} finally {
getContext().getThreadManager().enterGlobalLock(runningThread);
}
Thread.yield();
}

@Override
Original file line number Diff line number Diff line change
@@ -634,7 +634,7 @@ public Object select(RubyBasicObject readables, RubyBasicObject writables, RubyB
readableSet.set(fd);
}

final int result = getContext().getThreadManager().runUntilResult(new ThreadManager.BlockingActionWithoutGlobalLock<Integer>() {
final int result = getContext().getThreadManager().runUntilResult(new ThreadManager.BlockingAction<Integer>() {
@Override
public Integer block() throws InterruptedException {
return nativeSockets().select(
@@ -668,7 +668,7 @@ public Object selectNilReadables(RubyBasicObject readables, RubyBasicObject writ
writableSet.set(fd);
}

final int result = getContext().getThreadManager().runUntilResult(new ThreadManager.BlockingActionWithoutGlobalLock<Integer>() {
final int result = getContext().getThreadManager().runUntilResult(new ThreadManager.BlockingAction<Integer>() {
@Override
public Integer block() throws InterruptedException {
return nativeSockets().select(
Original file line number Diff line number Diff line change
@@ -143,14 +143,7 @@ public VMGCStartPrimitiveNode(RubyContext context, SourceSection sourceSection)

@Specialization
public RubyBasicObject vmGCStart() {
final RubyBasicObject runningThread = getContext().getThreadManager().leaveGlobalLock();

try {
System.gc();
} finally {
getContext().getThreadManager().enterGlobalLock(runningThread);
}

System.gc();
return nil();
}

@@ -510,7 +503,7 @@ public Object waitPID(final int input_pid, boolean no_hang) {
final int finalOptions = options;

// retry:
pid = getContext().getThreadManager().runUntilResult(new ThreadManager.BlockingActionWithoutGlobalLock<Integer>() {
pid = getContext().getThreadManager().runUntilResult(new ThreadManager.BlockingAction<Integer>() {
@Override
public Integer block() throws InterruptedException {
return posix().waitpid(input_pid, statusReference, finalOptions);
Original file line number Diff line number Diff line change
@@ -63,7 +63,7 @@ public ThreadFields(ThreadManager manager, FiberManager fiberManager, RubyBasicO
}
}

public ThreadFields fields;
public final ThreadFields fields;

public RubyThread(RubyBasicObject rubyClass, ThreadManager manager) {
super(rubyClass);
Original file line number Diff line number Diff line change
@@ -21,7 +21,7 @@
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.truffle.runtime.core.RubyBasicObject;
import org.jruby.truffle.runtime.subsystems.ThreadManager.BlockingActionWithoutGlobalLock;
import org.jruby.truffle.runtime.subsystems.ThreadManager.BlockingAction;

import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
@@ -105,9 +105,8 @@ private void runFinalizers() {
// Run in a loop

while (true) {
// Leave the global lock and wait on the finalizer queue

FinalizerReference finalizerReference = context.getThreadManager().runUntilResult(new BlockingActionWithoutGlobalLock<FinalizerReference>() {
// Wait on the finalizer queue
FinalizerReference finalizerReference = context.getThreadManager().runUntilResult(new BlockingAction<FinalizerReference>() {
@Override
public FinalizerReference block() throws InterruptedException {
return (FinalizerReference) finalizerQueue.remove();
Original file line number Diff line number Diff line change
@@ -16,7 +16,6 @@
import com.oracle.truffle.api.nodes.InvalidAssumptionException;
import com.oracle.truffle.api.nodes.Node;
import org.jruby.RubyThread.Status;
import org.jruby.truffle.nodes.RubyGuards;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.core.ThreadNodes;
import org.jruby.truffle.runtime.RubyContext;
@@ -83,40 +82,26 @@ private void poll(Node currentNode, boolean fromBlockingCall) {
return; // interrupt me later
}

SafepointAction deferredAction = assumptionInvalidated(currentNode, true, false);
SafepointAction deferredAction = assumptionInvalidated(currentNode, false);

// We're now running again normally, with the global lock, and can run deferred actions
// We're now running again normally and can run deferred actions
if (deferredAction != null) {
deferredAction.run(thread, currentNode);
}
}
}

private SafepointAction assumptionInvalidated(Node currentNode, boolean holdsGlobalLock, boolean isDrivingThread) {
private SafepointAction assumptionInvalidated(Node currentNode, boolean isDrivingThread) {
// Read these while in the safepoint.
SafepointAction deferredAction = deferred ? action : null;

RubyBasicObject thread = null;
if (holdsGlobalLock) {
thread = context.getThreadManager().leaveGlobalLock();
}

// TODO CS 27-Feb-15 how do we get thread if it wasn't holding the global lock?

try {
step(currentNode, thread, isDrivingThread);
} finally {
// The driving thread must acquire the global lock AFTER releasing the SafepointManager lock.
if (!isDrivingThread && holdsGlobalLock) {
context.getThreadManager().enterGlobalLock(thread);
}
}
step(currentNode, isDrivingThread);

return deferredAction;
}

private void step(Node currentNode, RubyBasicObject thread, boolean isDrivingThread) {
assert RubyGuards.isRubyThread(thread);
private void step(Node currentNode, boolean isDrivingThread) {
final RubyBasicObject thread = context.getThreadManager().getCurrentThread();

// wait other threads to reach their safepoint
phaser.arriveAndAwaitAdvance();
@@ -143,8 +128,6 @@ public void pauseAllThreadsAndExecute(Node currentNode, boolean deferred, Safepo
throw new IllegalStateException("Re-entered SafepointManager");
}

RubyBasicObject thread = context.getThreadManager().getCurrentThread();

// Need to lock interruptibly since we are in the registered threads.
while (!lock.tryLock()) {
poll(currentNode);
@@ -154,12 +137,11 @@ public void pauseAllThreadsAndExecute(Node currentNode, boolean deferred, Safepo
pauseAllThreadsAndExecute(currentNode, true, action, deferred);
} finally {
lock.unlock();
context.getThreadManager().enterGlobalLock(thread);
}

// Run deferred actions after leaving the SafepointManager lock and with the global lock.
// Run deferred actions after leaving the SafepointManager lock.
if (deferred) {
action.run(thread, currentNode);
action.run(context.getThreadManager().getCurrentThread(), currentNode);
}
}

@@ -169,6 +151,7 @@ public void pauseAllThreadsAndExecuteFromNonRubyThread(boolean deferred, Safepoi
}

assert !runningThreads.contains(Thread.currentThread());

// Just wait to grab the lock, since we are not in the registered threads.
lock.lock();
try {
@@ -183,7 +166,7 @@ public void pauseAllThreadsAndExecuteFromNonRubyThread(boolean deferred, Safepoi
}
}

private void pauseAllThreadsAndExecute(Node currentNode, boolean holdsGlobalLock, SafepointAction action, boolean deferred) {
private void pauseAllThreadsAndExecute(Node currentNode, boolean isRubyThread, SafepointAction action, boolean deferred) {
this.action = action;
this.deferred = deferred;

@@ -194,7 +177,7 @@ private void pauseAllThreadsAndExecute(Node currentNode, boolean holdsGlobalLock
assumption.invalidate();
interruptOtherThreads();

assumptionInvalidated(currentNode, holdsGlobalLock, true);
assumptionInvalidated(currentNode, true);
}

public void pauseThreadAndExecuteLater(final Thread thread, RubyNode currentNode, final SafepointAction action) {
Original file line number Diff line number Diff line change
@@ -44,7 +44,6 @@ public ThreadManager(RubyContext context) {
}

public void initialize() {
registerThread(rootThread);
ThreadNodes.start(rootThread);
FiberNodes.start(ThreadNodes.getRootFiber(rootThread));
}
@@ -53,32 +52,8 @@ public RubyBasicObject getRootThread() {
return rootThread;
}

/**
* Enters the global lock. Reentrant, but be aware that Ruby threads are not one-to-one with
* Java threads. Needs to be told which Ruby thread is becoming active as it can't work this out
* from the current Java thread. Remember to call {@link #leaveGlobalLock} again before
* blocking.
*/
@TruffleBoundary
public void enterGlobalLock(RubyBasicObject thread) {
assert RubyGuards.isRubyThread(thread);
currentThread.set(thread);
}

/**
* Leaves the global lock, returning the Ruby thread which has just stopped being the current
* thread. Remember to call {@link #enterGlobalLock} again with that returned thread before
* executing any Ruby code. You probably want to use this with a {@code finally} statement to
* make sure that happens
*/
@TruffleBoundary
public RubyBasicObject leaveGlobalLock() {
return currentThread.get();
}



public static interface BlockingActionWithoutGlobalLock<T> {
public static interface BlockingAction<T> {
public static boolean SUCCESS = true;

T block() throws InterruptedException;
@@ -93,20 +68,18 @@ public static interface BlockingActionWithoutGlobalLock<T> {
* @return the first non-null return value from {@code action}
*/
@TruffleBoundary
public <T> T runUntilResult(BlockingActionWithoutGlobalLock<T> action) {
public <T> T runUntilResult(BlockingAction<T> action) {
T result = null;

do {
final RubyBasicObject runningThread = leaveGlobalLock();
final RubyBasicObject runningThread = getCurrentThread();
ThreadNodes.setStatus(runningThread, Status.SLEEP);

try {
try {
result = action.block();
} finally {
ThreadNodes.setStatus(runningThread, Status.RUN);
// We need to enter the global lock before anything else!
enterGlobalLock(runningThread);
}
} catch (InterruptedException e) {
// We were interrupted, possibly by the SafepointManager.
@@ -117,23 +90,32 @@ public <T> T runUntilResult(BlockingActionWithoutGlobalLock<T> action) {
return result;
}

public void initializeCurrentThread(RubyBasicObject thread) {
assert RubyGuards.isRubyThread(thread);
currentThread.set(thread);
}

public RubyBasicObject getCurrentThread() {
return currentThread.get();
}

public synchronized void registerThread(RubyBasicObject thread) {
assert RubyGuards.isRubyThread(thread);
initializeCurrentThread(thread);
runningRubyThreads.add(thread);
}

public synchronized void unregisterThread(RubyBasicObject thread) {
assert RubyGuards.isRubyThread(thread);
runningRubyThreads.remove(thread);
currentThread.set(null);
}

public void shutdown() {
try {
killOtherThreads();
if (runningRubyThreads.size() > 1) {
killOtherThreads();
}
} finally {
ThreadNodes.getFiberManager(rootThread).shutdown();
FiberNodes.cleanup(ThreadNodes.getRootFiber(rootThread));
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@
package org.jruby.truffle.runtime.util;

import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.subsystems.ThreadManager.BlockingActionWithoutGlobalLock;
import org.jruby.truffle.runtime.subsystems.ThreadManager.BlockingAction;

import java.io.IOException;
import java.nio.channels.ClosedByInterruptException;
@@ -23,7 +23,7 @@ public class FileUtils {
public static byte[] readAllBytesInterruptedly(RubyContext context, String file) {
final Path path = Paths.get(file);

return context.getThreadManager().runUntilResult(new BlockingActionWithoutGlobalLock<byte[]>() {
return context.getThreadManager().runUntilResult(new BlockingAction<byte[]>() {
@Override
public byte[] block() throws InterruptedException {
try {
4 changes: 4 additions & 0 deletions truffle/src/main/ruby/core/rubinius/bootstrap/kernel.rb
Original file line number Diff line number Diff line change
@@ -38,4 +38,8 @@ def extend(mod)
self
end

def inspect
"#<#{self.class.name}"
end

end