Skip to content

Commit

Permalink
Showing 13 changed files with 200 additions and 24 deletions.
2 changes: 0 additions & 2 deletions spec/truffle/tags/core/threadgroup/add_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/threadgroup/enclose_tags.txt

This file was deleted.

2 changes: 0 additions & 2 deletions spec/truffle/tags/core/threadgroup/enclosed_tags.txt

This file was deleted.

3 changes: 3 additions & 0 deletions truffle/src/main/java/org/jruby/truffle/Layouts.java
Original file line number Diff line number Diff line change
@@ -86,6 +86,8 @@
import org.jruby.truffle.core.symbol.SymbolLayoutImpl;
import org.jruby.truffle.core.thread.ThreadBacktraceLocationLayout;
import org.jruby.truffle.core.thread.ThreadBacktraceLocationLayoutImpl;
import org.jruby.truffle.core.thread.ThreadGroupLayout;
import org.jruby.truffle.core.thread.ThreadGroupLayoutImpl;
import org.jruby.truffle.core.thread.ThreadLayout;
import org.jruby.truffle.core.thread.ThreadLayoutImpl;
import org.jruby.truffle.core.time.TimeLayout;
@@ -139,6 +141,7 @@ public abstract class Layouts {
public static final SymbolLayout SYMBOL = SymbolLayoutImpl.INSTANCE;
public static final ThreadLayout THREAD = ThreadLayoutImpl.INSTANCE;
public static final ThreadBacktraceLocationLayout THREAD_BACKTRACE_LOCATION = ThreadBacktraceLocationLayoutImpl.INSTANCE;
public static final ThreadGroupLayout THREAD_GROUP = ThreadGroupLayoutImpl.INSTANCE;
public static final TimeLayout TIME = TimeLayoutImpl.INSTANCE;
public static final UnboundMethodLayout UNBOUND_METHOD = UnboundMethodLayoutImpl.INSTANCE;
public static final WeakRefLayout WEAK_REF_LAYOUT = WeakRefLayoutImpl.INSTANCE;
13 changes: 13 additions & 0 deletions truffle/src/main/java/org/jruby/truffle/core/CoreLibrary.java
Original file line number Diff line number Diff line change
@@ -94,6 +94,7 @@
import org.jruby.truffle.core.symbol.SymbolNodesFactory;
import org.jruby.truffle.core.thread.ThreadBacktraceLocationLayoutImpl;
import org.jruby.truffle.core.thread.ThreadBacktraceLocationNodesFactory;
import org.jruby.truffle.core.thread.ThreadGroupNodesFactory;
import org.jruby.truffle.core.thread.ThreadNodesFactory;
import org.jruby.truffle.core.time.TimeNodesFactory;
import org.jruby.truffle.core.tracepoint.TracePointNodesFactory;
@@ -225,6 +226,8 @@ public class CoreLibrary {
private final DynamicObject systemExitClass;
private final DynamicObject threadClass;
private final DynamicObjectFactory threadFactory;
private final DynamicObject threadGroupClass;
private final DynamicObjectFactory threadGroupFactory;
private final DynamicObject threadBacktraceClass;
private final DynamicObject threadBacktraceLocationClass;
private final DynamicObjectFactory threadBacktraceLocationFactory;
@@ -528,6 +531,11 @@ public CoreLibrary(RubyContext context) {
threadFactory = Layouts.THREAD.createThreadShape(threadClass, threadClass);
Layouts.CLASS.setInstanceFactoryUnsafe(threadClass, threadFactory);


threadGroupClass = defineClass("ThreadGroup");
threadGroupFactory = Layouts.THREAD_GROUP.createThreadGroupShape(threadGroupClass, threadGroupClass);
Layouts.CLASS.setInstanceFactoryUnsafe(threadGroupClass, threadGroupFactory);

threadBacktraceClass = defineClass(threadClass, objectClass, "Backtrace");
threadBacktraceLocationClass = defineClass(threadBacktraceClass, objectClass, "Location");
threadBacktraceLocationFactory = ThreadBacktraceLocationLayoutImpl.INSTANCE.createThreadBacktraceLocationShape(threadBacktraceLocationClass, threadBacktraceLocationClass);
@@ -747,6 +755,7 @@ public void addCoreMethods(PrimitiveManager primitiveManager) {
SymbolNodesFactory.getFactories(),
SystemCallErrorNodesFactory.getFactories(),
ThreadBacktraceLocationNodesFactory.getFactories(),
ThreadGroupNodesFactory.getFactories(),
ThreadNodesFactory.getFactories(),
TimeNodesFactory.getFactories(),
TracePointNodesFactory.getFactories(),
@@ -1293,6 +1302,10 @@ public DynamicObjectFactory getThreadFactory() {
return threadFactory;
}

public DynamicObjectFactory getThreadGroupFactory() {
return threadGroupFactory;
}

public DynamicObject getTypeErrorClass() {
return typeErrorClass;
}
Original file line number Diff line number Diff line change
@@ -794,6 +794,22 @@ public DynamicObject threadErrorAlreadyLocked(Node currentNode) {
return threadError("Attempt to unlock a mutex which is locked by another thread", currentNode);
}

public DynamicObject threadErrorFrozenToThreadGroup(Node currentNode) {
return threadError("can't move to the frozen thread group", currentNode);
}

public DynamicObject threadErrorFrozenFromThreadGroup(Node currentNode) {
return threadError("can't move from the frozen thread group", currentNode);
}

public DynamicObject threadErrorToEnclosedThreadGroup(Node currentNode) {
return threadError("can't move to the enclosed thread group", currentNode);
}

public DynamicObject threadErrorFromEnclosedThreadGroup(Node currentNode) {
return threadError("can't move from the enclosed thread group", currentNode);
}

// SecurityError

@TruffleBoundary
Original file line number Diff line number Diff line change
@@ -14,6 +14,7 @@
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.utilities.CyclicAssumption;
import org.jruby.RubyGC;
import org.jruby.truffle.Layouts;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.core.thread.ThreadManager;
import org.jruby.truffle.language.control.RaiseException;
@@ -92,7 +93,8 @@ public synchronized void defineFinalizer(DynamicObject object, Object callable)
if (finalizerThread == null) {
// TODO(CS): should we be running this in a real Ruby thread?

finalizerThread = ThreadManager.createRubyThread(context);
final DynamicObject rootGroup = Layouts.THREAD.getThreadGroup(context.getThreadManager().getRootThread());
finalizerThread = ThreadManager.createRubyThread(context, rootGroup);
ThreadManager.initialize(finalizerThread, context, null, "finalizer", new Runnable() {
@Override
public void run() {
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package org.jruby.truffle.core.thread;

import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.object.DynamicObjectFactory;
import com.oracle.truffle.api.object.dsl.Layout;
import org.jruby.truffle.core.basicobject.BasicObjectLayout;

@Layout
public interface ThreadGroupLayout extends BasicObjectLayout {

DynamicObjectFactory createThreadGroupShape(
DynamicObject logicalClass,
DynamicObject metaClass);

DynamicObject createThreadGroup(
DynamicObjectFactory factory,
boolean enclosed);

boolean getEnclosed(DynamicObject object);

void setEnclosed(DynamicObject object, boolean value);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package org.jruby.truffle.core.thread;

import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.Layouts;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.builtins.CoreClass;
import org.jruby.truffle.builtins.CoreMethod;
import org.jruby.truffle.builtins.CoreMethodArrayArgumentsNode;
import org.jruby.truffle.language.control.RaiseException;
import org.jruby.truffle.language.objects.AllocateObjectNode;
import org.jruby.truffle.language.objects.IsFrozenNode;
import org.jruby.truffle.language.objects.IsFrozenNodeGen;

import java.util.ArrayList;
import java.util.List;

@CoreClass("ThreadGroup")
public abstract class ThreadGroupNodes {

@CoreMethod(names = "allocate", constructor = true)
public abstract static class AllocateNode extends CoreMethodArrayArgumentsNode {

@Child private AllocateObjectNode allocateObjectNode;

public AllocateNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
allocateObjectNode = AllocateObjectNode.create();
}

@Specialization
public DynamicObject allocateThreadGroup(DynamicObject rubyClass) {
return allocateObjectNode.allocate(rubyClass, false);
}

}

@CoreMethod(names = "enclose")
public abstract static class EncloseNode extends CoreMethodArrayArgumentsNode {

@Specialization
public DynamicObject enclose(DynamicObject group) {
Layouts.THREAD_GROUP.setEnclosed(group, true);
return group;
}

}

@CoreMethod(names = "enclosed?")
public abstract static class EnclosedNode extends CoreMethodArrayArgumentsNode {

@Specialization
public boolean enclosed(DynamicObject group) {
return Layouts.THREAD_GROUP.getEnclosed(group);
}

}

@CoreMethod(names = "list")
public abstract static class ListNode extends CoreMethodArrayArgumentsNode {

@Specialization
public DynamicObject list(DynamicObject group) {
final Object[] threads = getContext().getThreadManager().getThreadList();
List<Object> results = new ArrayList<>();
for (Object thread : threads) {
if (Layouts.THREAD.getThreadGroup((DynamicObject) thread) == group) {
results.add(thread);
}
}
return Layouts.ARRAY.createArray(coreLibrary().getArrayFactory(), results.toArray(), results.size());
}

}

@CoreMethod(names = "add", required = 1)
public abstract static class AddNode extends CoreMethodArrayArgumentsNode {

@Child private IsFrozenNode isFrozenToNode;
@Child private IsFrozenNode isFrozenFromNode;

public AddNode(RubyContext context, SourceSection sourceSection) {
isFrozenToNode = IsFrozenNodeGen.create(context, sourceSection, null);
isFrozenFromNode = IsFrozenNodeGen.create(context, sourceSection, null);
}

@Specialization
public DynamicObject add(DynamicObject toGroup, DynamicObject thread) {


if (isFrozenToNode.executeIsFrozen(toGroup)) {
throw new RaiseException(coreExceptions().threadErrorFrozenToThreadGroup(this));
}

if (Layouts.THREAD_GROUP.getEnclosed(toGroup)) {
throw new RaiseException(coreExceptions().threadErrorToEnclosedThreadGroup(this));
}

final DynamicObject fromGroup = Layouts.THREAD.getThreadGroup(thread);

if (fromGroup == null) {
return nil();
}

if (isFrozenFromNode.executeIsFrozen(fromGroup)) {
throw new RaiseException(coreExceptions().threadErrorFrozenFromThreadGroup(this));
}

if (Layouts.THREAD_GROUP.getEnclosed(fromGroup)) {
throw new RaiseException(coreExceptions().threadErrorFromEnclosedThreadGroup(this));
}
Layouts.THREAD.setThreadGroup(thread, toGroup);
return toGroup;
}

}


}
Original file line number Diff line number Diff line change
@@ -45,7 +45,8 @@ DynamicObject createThread(
@Nullable @Volatile DynamicObject exception,
@Nullable @Volatile Object value,
AtomicBoolean wakeUp,
@Volatile int priority);
@Volatile int priority,
@Nullable DynamicObject threadGroup);

boolean isThread(ObjectType objectType);
boolean isThread(DynamicObject object);
@@ -82,4 +83,7 @@ DynamicObject createThread(
int getPriority(DynamicObject object);
void setPriority(DynamicObject object, int value);

DynamicObject getThreadGroup(DynamicObject object);
void setThreadGroup(DynamicObject object, DynamicObject value);

}
Original file line number Diff line number Diff line change
@@ -49,13 +49,14 @@ public class ThreadManager {

public ThreadManager(RubyContext context) {
this.context = context;
this.rootThread = createRubyThread(context);
final DynamicObject group = Layouts.THREAD_GROUP.createThreadGroup(context.getCoreLibrary().getThreadGroupFactory(), false);
this.rootThread = createRubyThread(context, group);
}

public static final InterruptMode DEFAULT_INTERRUPT_MODE = InterruptMode.IMMEDIATE;
public static final Status DEFAULT_STATUS = Status.RUN;

public static DynamicObject createRubyThread(RubyContext context) {
public static DynamicObject createRubyThread(RubyContext context, DynamicObject group) {
final DynamicObject object = Layouts.THREAD.createThread(
context.getCoreLibrary().getThreadFactory(),
createThreadLocals(context),
@@ -69,7 +70,8 @@ public static DynamicObject createRubyThread(RubyContext context) {
null,
null,
new AtomicBoolean(false),
0);
0,
group);

Layouts.THREAD.setFiberManagerUnsafe(object, new FiberManager(context, object)); // Because it is cyclic

Original file line number Diff line number Diff line change
@@ -113,6 +113,15 @@ public DynamicObject current() {

}

@CoreMethod(names = "group")
public abstract static class GroupNode extends CoreMethodArrayArgumentsNode {

@Specialization
public DynamicObject group(DynamicObject thread) {
return Layouts.THREAD.getThreadGroup(thread);
}
}

@CoreMethod(names = { "kill", "exit", "terminate" }, unsafe = UnsafeGroup.THREADS)
public abstract static class KillNode extends CoreMethodArrayArgumentsNode {

@@ -412,6 +421,7 @@ public DynamicObject allocate(
DynamicObject rubyClass,
@Cached("create()") AllocateObjectNode allocateObjectNode,
@Cached("createReadAbortOnExceptionNode()") ReadObjectFieldNode readAbortOnException ) {
final DynamicObject rootGroup = Layouts.THREAD.getThreadGroup(getContext().getThreadManager().getRootThread());
final DynamicObject object = allocateObjectNode.allocate(
rubyClass,
ThreadManager.createThreadLocals(getContext()),
@@ -425,7 +435,8 @@ public DynamicObject allocate(
new AtomicReference<>(null),
new AtomicReference<>(null),
new AtomicBoolean(false),
new AtomicInteger(0));
new AtomicInteger(0),
rootGroup);

Layouts.THREAD.setFiberManagerUnsafe(object, new FiberManager(getContext(), object)); // Because it is cyclic

13 changes: 0 additions & 13 deletions truffle/src/main/ruby/core/thread.rb
Original file line number Diff line number Diff line change
@@ -351,16 +351,3 @@ def freeze

end

class ThreadGroup

attr_reader :list

def initialize
@list = []
end

def add(thread)
@list.push thread
end

end

0 comments on commit efe32c0

Please sign in to comment.