Skip to content

Commit

Permalink
Showing 7 changed files with 185 additions and 130 deletions.
111 changes: 54 additions & 57 deletions core/src/main/java/org/jruby/truffle/nodes/core/KernelNodes.java
Original file line number Diff line number Diff line change
@@ -32,6 +32,7 @@
import org.jruby.truffle.runtime.core.RubyArray;
import org.jruby.truffle.runtime.core.RubyHash;
import org.jruby.truffle.runtime.subsystems.*;
import org.jruby.truffle.runtime.util.Supplier;

@CoreClass(name = "Kernel")
public abstract class KernelNodes {
@@ -390,17 +391,17 @@ public RubyString gets(VirtualFrame frame) {

final ThreadManager threadManager = context.getThreadManager();

String line;
final String line = getContext().outsideGlobalLock(new Supplier<String>() {

final RubyThread runningThread = threadManager.leaveGlobalLock();

try {
line = gets(context);
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
threadManager.enterGlobalLock(runningThread);
}
@Override
public String get() {
try {
return gets(context);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
});

final RubyString rubyLine = context.makeString(line);

@@ -559,20 +560,19 @@ public PNode(PNode prev) {
}

@Specialization
public NilPlaceholder p(VirtualFrame frame, Object[] args) {
public NilPlaceholder p(final VirtualFrame frame, final Object[] args) {
notDesignedForCompilation();

final ThreadManager threadManager = getContext().getThreadManager();

final RubyThread runningThread = threadManager.leaveGlobalLock();
getContext().outsideGlobalLock(new Runnable() {

try {
for (Object arg : args) {
getContext().getRuntime().getInstanceConfig().getOutput().println(inspect.call(frame, arg, "inspect", null));
@Override
public void run() {
for (Object arg : args) {
getContext().getRuntime().getInstanceConfig().getOutput().println(inspect.call(frame, arg, "inspect", null));
}
}
} finally {
threadManager.enterGlobalLock(runningThread);
}

});

return NilPlaceholder.INSTANCE;
}
@@ -594,22 +594,21 @@ public PrintNode(PrintNode prev) {
}

@Specialization
public NilPlaceholder print(VirtualFrame frame, Object[] args) {
final ThreadManager threadManager = getContext().getThreadManager();

final RubyThread runningThread = threadManager.leaveGlobalLock();
public NilPlaceholder print(final VirtualFrame frame, final Object[] args) {
getContext().outsideGlobalLock(new Runnable() {

try {
for (Object arg : args) {
try {
getContext().getRuntime().getInstanceConfig().getOutput().write(((RubyString) toS.call(frame, arg, "to_s", null)).getBytes().bytes());
} catch (IOException e) {
throw new RuntimeException(e);
@Override
public void run() {
for (Object arg : args) {
try {
getContext().getRuntime().getInstanceConfig().getOutput().write(((RubyString) toS.call(frame, arg, "to_s", null)).getBytes().bytes());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
} finally {
threadManager.enterGlobalLock(runningThread);
}

});

return NilPlaceholder.INSTANCE;
}
@@ -630,19 +629,18 @@ public PrintfNode(PrintfNode prev) {
public NilPlaceholder printf(Object[] args) {
notDesignedForCompilation();

final ThreadManager threadManager = getContext().getThreadManager();

if (args.length > 0) {
final String format = ((RubyString) args[0]).toString();
final String format = args[0].toString();
final List<Object> values = Arrays.asList(args).subList(1, args.length);

final RubyThread runningThread = threadManager.leaveGlobalLock();
getContext().outsideGlobalLock(new Runnable() {

try {
StringFormatter.format(getContext().getRuntime().getInstanceConfig().getOutput(), format, values);
} finally {
threadManager.enterGlobalLock(runningThread);
}
@Override
public void run() {
StringFormatter.format(getContext().getRuntime().getInstanceConfig().getOutput(), format, values);
}

});
}

return NilPlaceholder.INSTANCE;
@@ -867,28 +865,27 @@ public double sleep(double duration) {
}

@SlowPath
private double doSleep(double duration) {
private double doSleep(final double duration) {
notDesignedForCompilation();

final RubyContext context = getContext();
return getContext().outsideGlobalLock(new Supplier<Double>() {

final RubyThread runningThread = context.getThreadManager().leaveGlobalLock();
@Override
public Double get() {
final long start = System.nanoTime();

try {
final long start = System.nanoTime();
try {
Thread.sleep((long) (duration * 1000));
} catch (InterruptedException e) {
// Ignore interruption
}

try {
Thread.sleep((long) (duration * 1000));
} catch (InterruptedException e) {
// Ignore interruption
}
final long end = System.nanoTime();

final long end = System.nanoTime();
return (end - start) / 1e9;
}

return (end - start) / 1e9;
} finally {
context.getThreadManager().enterGlobalLock(runningThread);
}
});
}

@Specialization
Original file line number Diff line number Diff line change
@@ -135,13 +135,14 @@ public NilPlaceholder garbageCollect() {
private NilPlaceholder doGC() {
notDesignedForCompilation();

final RubyThread runningThread = getContext().getThreadManager().leaveGlobalLock();
getContext().outsideGlobalLock(new Runnable() {

try {
System.gc();
} finally {
getContext().getThreadManager().enterGlobalLock(runningThread);
}
@Override
public void run() {
System.gc();
}

});

return NilPlaceholder.INSTANCE;
}
9 changes: 9 additions & 0 deletions core/src/main/java/org/jruby/truffle/runtime/RubyContext.java
Original file line number Diff line number Diff line change
@@ -38,6 +38,7 @@
import org.jruby.truffle.runtime.core.RubySymbol;
import org.jruby.truffle.runtime.core.RubyBasicObject;
import org.jruby.truffle.runtime.subsystems.*;
import org.jruby.truffle.runtime.util.Supplier;
import org.jruby.truffle.translator.TranslatorDriver;
import org.jruby.util.ByteList;
import org.jruby.util.cli.Options;
@@ -299,6 +300,14 @@ public ThreadManager getThreadManager() {
return threadManager;
}

public void outsideGlobalLock(Runnable runnable) {
threadManager.outsideGlobalLock(runnable);
}

public <T> T outsideGlobalLock(Supplier<T> supplier) {
return threadManager.outsideGlobalLock(supplier);
}

public TranslatorDriver getTranslator() {
return translator;
}
23 changes: 12 additions & 11 deletions core/src/main/java/org/jruby/truffle/runtime/core/RubyThread.java
Original file line number Diff line number Diff line change
@@ -103,20 +103,21 @@ public void shutdown() {
}

public void join() {
final RubyThread runningThread = getRubyClass().getContext().getThreadManager().leaveGlobalLock();
getRubyClass().getContext().outsideGlobalLock(new Runnable() {

try {
while (true) {
try {
finished.await();
break;
} catch (InterruptedException e) {
// Await again
@Override
public void run() {
while (true) {
try {
finished.await();
break;
} catch (InterruptedException e) {
// Await again
}
}
}
} finally {
runningThread.manager.enterGlobalLock(runningThread);
}

});

if (exception != null) {
throw new RaiseException(exception);
Original file line number Diff line number Diff line change
@@ -90,6 +90,8 @@ public void defineFinalizer(RubyBasicObject object, RubyProc proc) {
// If there is no finalizer thread, start one

if (finalizerThread == null) {
// TODO(CS): should we be running this in a real Ruby thread?

finalizerThread = new RubyThread(context.getCoreLibrary().getThreadClass(), context.getThreadManager());

finalizerThread.initialize(new Runnable() {
@@ -213,84 +215,90 @@ public void checkSafepoint() {
try {
notStoppingAssumption.check();
} catch (InvalidAssumptionException e) {
final RubyThread thread = context.getThreadManager().leaveGlobalLock();

while (true) {
try {
stoppedBarrier.await();
break;
} catch (InterruptedException | BrokenBarrierException e2) {
}
}

synchronized (liveObjects) {
visitCallStack(visitor);
}
context.outsideGlobalLock(new Runnable() {

while (true) {
try {
markedBarrier.await();
break;
} catch (InterruptedException | BrokenBarrierException e2) {
@Override
public void run() {
while (true) {
try {
stoppedBarrier.await();
break;
} catch (InterruptedException | BrokenBarrierException e2) {
}
}

synchronized (liveObjects) {
visitCallStack(visitor);
}

while (true) {
try {
markedBarrier.await();
break;
} catch (InterruptedException | BrokenBarrierException e2) {
}
}

// TODO(CS): error recovery
}
}

// TODO(CS): error recovery

context.getThreadManager().enterGlobalLock(thread);
});
}
}

public Map<Long, RubyBasicObject> collectLiveObjects() {
RubyNode.notDesignedForCompilation();

synchronized (context.getThreadManager()) {
final RubyThread thread = context.getThreadManager().leaveGlobalLock();
context.outsideGlobalLock(new Runnable() {

liveObjects = new HashMap<Long, RubyBasicObject>();
@Override
public void run() {
liveObjects = new HashMap<>();

visitor = new ObjectGraphVisitor() {
visitor = new ObjectGraphVisitor() {

@Override
public boolean visit(RubyBasicObject object) {
return liveObjects.put(object.getObjectID(), object) == null;
}
@Override
public boolean visit(RubyBasicObject object) {
return liveObjects.put(object.getObjectID(), object) == null;
}

};
};

stoppedBarrier = new CyclicBarrier(2);
markedBarrier = new CyclicBarrier(2);
stoppedBarrier = new CyclicBarrier(2);
markedBarrier = new CyclicBarrier(2);

notStoppingAssumption.invalidate();
notStoppingAssumption.invalidate();

while (true) {
try {
stoppedBarrier.await();
break;
} catch (InterruptedException | BrokenBarrierException e){
}
}
while (true) {
try {
stoppedBarrier.await();
break;
} catch (InterruptedException | BrokenBarrierException e) {
}
}

synchronized (liveObjects) {
context.getCoreLibrary().getGlobalVariablesObject().visitObjectGraph(visitor);
context.getCoreLibrary().getMainObject().visitObjectGraph(visitor);
context.getCoreLibrary().getObjectClass().visitObjectGraph(visitor);
visitCallStack(visitor);
}
synchronized (liveObjects) {
context.getCoreLibrary().getGlobalVariablesObject().visitObjectGraph(visitor);
context.getCoreLibrary().getMainObject().visitObjectGraph(visitor);
context.getCoreLibrary().getObjectClass().visitObjectGraph(visitor);
visitCallStack(visitor);
}

notStoppingAssumption = Truffle.getRuntime().createAssumption();
notStoppingAssumption = Truffle.getRuntime().createAssumption();

while (true) {
try {
markedBarrier.await();
break;
} catch (InterruptedException | BrokenBarrierException e){
}
}
while (true) {
try {
markedBarrier.await();
break;
} catch (InterruptedException | BrokenBarrierException e) {
}
}

// TODO(CS): error recovery
// TODO(CS): error recovery
}

context.getThreadManager().enterGlobalLock(thread);
});

return Collections.unmodifiableMap(liveObjects);
}
Original file line number Diff line number Diff line change
@@ -15,6 +15,7 @@

import org.jruby.truffle.runtime.*;
import org.jruby.truffle.runtime.core.*;
import org.jruby.truffle.runtime.util.Supplier;

/**
* Manages Ruby {@code Thread} objects.
@@ -61,6 +62,28 @@ public RubyThread leaveGlobalLock() {
return result;
}

public void outsideGlobalLock(final Runnable runnable) {
outsideGlobalLock(new Supplier<Void>() {

@Override
public Void get() {
runnable.run();
return null;
}

});
}

public <T> T outsideGlobalLock(Supplier<T> supplier) {
final RubyThread runningThread = leaveGlobalLock();

try {
return supplier.get();
} finally {
enterGlobalLock(runningThread);
}
}

public RubyThread getCurrentThread() {
return currentThread;
}
16 changes: 16 additions & 0 deletions core/src/main/java/org/jruby/truffle/runtime/util/Supplier.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.runtime.util;

public interface Supplier<T> {

T get();

}

0 comments on commit fb95f9a

Please sign in to comment.